diff --git a/app/(connected)/(with-sidebar)/(with-chat)/etablissement/EtablissementPage.tsx b/app/(connected)/(with-sidebar)/(with-chat)/etablissement/EtablissementPage.tsx index c990dacb7..611c55be7 100644 --- a/app/(connected)/(with-sidebar)/(with-chat)/etablissement/EtablissementPage.tsx +++ b/app/(connected)/(with-sidebar)/(with-chat)/etablissement/EtablissementPage.tsx @@ -146,7 +146,15 @@ function EtablissementPage() { )} )} - + {jeune.dateDerniereActivite && toRelativeDateTime(jeune.dateDerniereActivite)} @@ -157,10 +165,7 @@ function EtablissementPage() { ))} diff --git a/app/(connected)/(with-sidebar)/(with-chat)/mes-jeunes/listes-de-diffusion/ListesDiffusionPage.tsx b/app/(connected)/(with-sidebar)/(with-chat)/mes-jeunes/listes-de-diffusion/ListesDiffusionPage.tsx index 91e2db31b..78889f71a 100644 --- a/app/(connected)/(with-sidebar)/(with-chat)/mes-jeunes/listes-de-diffusion/ListesDiffusionPage.tsx +++ b/app/(connected)/(with-sidebar)/(with-chat)/mes-jeunes/listes-de-diffusion/ListesDiffusionPage.tsx @@ -140,7 +140,7 @@ function ListesDiffusionPage({ listesDiffusion }: ListesDiffusionPageProps) { {liste.beneficiaires.length} destinataire(s) ))} diff --git a/app/(connected)/(with-sidebar)/(without-chat)/agenda/sessions/[idSession]/cloture/ClotureSessionPage.tsx b/app/(connected)/(with-sidebar)/(without-chat)/agenda/sessions/[idSession]/cloture/ClotureSessionPage.tsx index 5df3eed9b..ade54f564 100644 --- a/app/(connected)/(with-sidebar)/(without-chat)/agenda/sessions/[idSession]/cloture/ClotureSessionPage.tsx +++ b/app/(connected)/(with-sidebar)/(without-chat)/agenda/sessions/[idSession]/cloture/ClotureSessionPage.tsx @@ -229,6 +229,8 @@ function ClotureSessionPage({ : 'before:fixed before:inset-0 before:z-10 cursor-pointer' }`} > + {/* FIXME title != label */} + {/* FIXME title pas hoverable à cause de "before:z-10" ? */} @@ -86,7 +80,7 @@ export default function ActionRow({ ) diff --git a/components/action/ActionRowPilotage.tsx b/components/action/ActionRowPilotage.tsx index dd943250e..dfa563583 100644 --- a/components/action/ActionRowPilotage.tsx +++ b/components/action/ActionRowPilotage.tsx @@ -50,7 +50,7 @@ export default function ActionRowPilotage({ ) diff --git a/components/favoris/offres/OffreRow.tsx b/components/favoris/offres/OffreRow.tsx index 2abf1a1d3..b59090417 100644 --- a/components/favoris/offres/OffreRow.tsx +++ b/components/favoris/offres/OffreRow.tsx @@ -21,7 +21,7 @@ export default function OffreRow({ offre }: { offre: Offre }) { ) diff --git a/components/jeune/OngletDemarches.tsx b/components/jeune/OngletDemarches.tsx index 60de627bf..4de81c626 100644 --- a/components/jeune/OngletDemarches.tsx +++ b/components/jeune/OngletDemarches.tsx @@ -297,7 +297,7 @@ function DemarcheRow({ ) diff --git a/components/jeune/TableauBeneficiairesMilo.tsx b/components/jeune/TableauBeneficiairesMilo.tsx index 3e0f100b1..f73139dbc 100644 --- a/components/jeune/TableauBeneficiairesMilo.tsx +++ b/components/jeune/TableauBeneficiairesMilo.tsx @@ -195,7 +195,7 @@ export default function TableauBeneficiairesMilo({ diff --git a/components/jeune/TableauBeneficiairesPasMilo.tsx b/components/jeune/TableauBeneficiairesPasMilo.tsx index f65bd0ac8..c16ee8e36 100644 --- a/components/jeune/TableauBeneficiairesPasMilo.tsx +++ b/components/jeune/TableauBeneficiairesPasMilo.tsx @@ -126,7 +126,7 @@ export default function TableauBeneficiairesPasMilo({ diff --git a/components/pilotage/TableauAnimationsAClore.tsx b/components/pilotage/TableauAnimationsAClore.tsx index 65c659e53..bda4317be 100644 --- a/components/pilotage/TableauAnimationsAClore.tsx +++ b/components/pilotage/TableauAnimationsAClore.tsx @@ -44,7 +44,7 @@ export default function TableauAnimationsAClore({ ))} diff --git a/components/pilotage/TableauSessionsImilo.tsx b/components/pilotage/TableauSessionsImilo.tsx index e65dadda4..c351f3413 100644 --- a/components/pilotage/TableauSessionsImilo.tsx +++ b/components/pilotage/TableauSessionsImilo.tsx @@ -37,7 +37,7 @@ export default function TableauSessionsImilo({ ))} diff --git a/components/rdv/AgendaRow.tsx b/components/rdv/AgendaRow.tsx index ad4b8794c..1beb2677b 100644 --- a/components/rdv/AgendaRow.tsx +++ b/components/rdv/AgendaRow.tsx @@ -32,7 +32,7 @@ export function AgendaRow({ evenement }: { evenement: EvenementListItem }) {
{longMonthDate}
- {heure} -{' '} + {heure} - ) @@ -118,8 +118,8 @@ function Inscrits({ if (!aUneCapaciteLimite) return (

- {nombreParticipants} inscrit - {aPlusieursParticipants ? 's' : ''} + {nombreParticipants}{' '} + {aPlusieursParticipants ? 'inscrits' : 'inscrit'}

) else if (aUneCapaciteLimite && aAtteintLaCapaciteLimite) @@ -127,8 +127,8 @@ function Inscrits({ else return (

- {nombreParticipants} inscrit - {nombreParticipants !== 1 ? 's' : ''} /{maxParticipants} + {nombreParticipants}{' '} + {nombreParticipants !== 1 ? 'inscrits' : 'inscrit'} /{maxParticipants}

) } diff --git a/components/rdv/AnimationCollectiveRow.tsx b/components/rdv/AnimationCollectiveRow.tsx index de0bbc6fd..f8939c170 100644 --- a/components/rdv/AnimationCollectiveRow.tsx +++ b/components/rdv/AnimationCollectiveRow.tsx @@ -16,12 +16,7 @@ import { } from 'interfaces/evenement' import { trackEvent } from 'utils/analytics/matomo' import { useConseiller } from 'utils/conseiller/conseillerContext' -import { - toFrenchDuration, - toFrenchTime, - toLongMonthDate, - toMonthday, -} from 'utils/date' +import { toFrenchDuration, toFrenchTime, toLongMonthDate } from 'utils/date' import { usePortefeuille } from 'utils/portefeuilleContext' export function AnimationCollectiveRow({ @@ -39,9 +34,10 @@ export function AnimationCollectiveRow({ animationCollective.estCache ?? false ) - function getHref(ac: AnimationCollective): string { - if (ac.isSession) return `agenda/sessions/${ac.id}` - else return `/mes-jeunes/edition-rdv?idRdv=${ac.id}` + function getHref(): string { + if (animationCollective.isSession) + return `agenda/sessions/${animationCollective.id}` + else return `/mes-jeunes/edition-rdv?idRdv=${animationCollective.id}` } async function permuterVisibiliteSession(visibilite: boolean) { @@ -65,7 +61,9 @@ export function AnimationCollectiveRow({
{toLongMonthDate(date)}
- {toFrenchTime(date)} -{' '} + + {toFrenchTime(date)} -{' '} + ) @@ -134,14 +132,8 @@ function statusProps({ type, statut }: AnimationCollective): { } } -function labelLien(ac: AnimationCollective): string { - return `Consulter ${ac.type} ${ac.titre} du ${toMonthday( - ac.date - )} à ${toFrenchTime(ac.date)}` -} - -function TagStatut(ac: AnimationCollective): ReactElement { - const { label, color } = statusProps(ac) +function TagStatut(animationCollective: AnimationCollective): ReactElement { + const { label, color } = statusProps(animationCollective) return ( <_TagStatut label={label} @@ -212,8 +204,8 @@ function Inscrits({
{!aUneCapaciteLimite && ( <> - {nombreParticipants} inscrit - {aPlusieursParticipants ? 's' : ''} + {nombreParticipants}{' '} + {aPlusieursParticipants ? 'inscrits' : 'inscrit'} )} @@ -223,8 +215,9 @@ function Inscrits({ {aUneCapaciteLimite && !aAtteintLaCapaciteLimite && ( <> - {nombreParticipants} inscrit - {nombreParticipants !== 1 ? 's' : ''} /{nombreMaxParticipants} + {nombreParticipants}{' '} + {nombreParticipants !== 1 ? 'inscrits' : 'inscrit'} / + {nombreMaxParticipants} )}
diff --git a/components/rdv/EvenementRow.tsx b/components/rdv/EvenementRow.tsx index be1752445..1af225301 100644 --- a/components/rdv/EvenementRow.tsx +++ b/components/rdv/EvenementRow.tsx @@ -7,24 +7,23 @@ import { TagType } from 'components/ui/Indicateurs/Tag' import TD from 'components/ui/Table/TD' import TDLink from 'components/ui/Table/TDLink' import TR from 'components/ui/Table/TR' -import { - BaseBeneficiaire, - getNomBeneficiaireComplet, -} from 'interfaces/beneficiaire' import { EvenementListItem } from 'interfaces/evenement' -import { toFrenchTime, toMonthday, toShortDate } from 'utils/date' +import { + toFrenchDuration, + toFrenchTime, + toMonthday, + toShortDate, +} from 'utils/date' interface EvenementRowProps { evenement: EvenementListItem idConseiller: string - beneficiaire: BaseBeneficiaire withIndicationPresenceBeneficiaire?: boolean } export function EvenementRow({ evenement, idConseiller, - beneficiaire, withIndicationPresenceBeneficiaire = false, }: EvenementRowProps) { const pathPrefix = usePathname()?.startsWith('/etablissement') @@ -34,9 +33,8 @@ export function EvenementRow({ const date = DateTime.fromISO(evenement.date) const shortDate = toShortDate(date) const fullDate = toMonthday(date) - const timeAndDuration = `${toFrenchTime(date)} - ${evenement.duree} min` - - const labelBeneficiaires = getNomBeneficiaireComplet(beneficiaire) + const timeAndDuration = `${toFrenchTime(date)} - ${toFrenchDuration(evenement.duree)}` + const timeAndDurationA11y = `${toFrenchTime(date, { a11y: true })} - ${toFrenchDuration(evenement.duree, { a11y: true })}` const urlRdv = pathPrefix + '/edition-rdv?idRdv=' + evenement.id const urlSessionMilo = '/agenda/sessions/' + evenement.id @@ -44,7 +42,7 @@ export function EvenementRow({ return ( {shortDate} - {timeAndDuration} @@ -97,32 +95,22 @@ export function EvenementRow({ - {evenement.createur?.id === idConseiller && ( - <> - oui - - - )} - {evenement.createur?.id !== idConseiller && ( - <> - non - - - )} + + {evenement.createur?.id === idConseiller ? 'oui' : 'non'} + ) diff --git a/components/rdv/TableauRdvsBeneficiaire.tsx b/components/rdv/TableauRdvsBeneficiaire.tsx index c6af6d3e7..3f9afb56b 100644 --- a/components/rdv/TableauRdvsBeneficiaire.tsx +++ b/components/rdv/TableauRdvsBeneficiaire.tsx @@ -74,7 +74,6 @@ export default function TableauRdvsBeneficiaire({ diff --git a/components/ui/IconComponent.tsx b/components/ui/IconComponent.tsx index 96b6edf66..7fd8611a0 100644 --- a/components/ui/IconComponent.tsx +++ b/components/ui/IconComponent.tsx @@ -242,7 +242,11 @@ type IconComponentProps = ComponentPropsWithoutRef<'svg'> & { name: IconName title?: string } -export default function IconComponent({ name, ...props }: IconComponentProps) { +export default function IconComponent({ + name, + className, + ...props +}: IconComponentProps) { const Icon = iconsByName[name] - return + return } diff --git a/components/ui/Table/TD.tsx b/components/ui/Table/TD.tsx index 6bcfe68a2..733145a25 100644 --- a/components/ui/Table/TD.tsx +++ b/components/ui/Table/TD.tsx @@ -1,23 +1,28 @@ -import React, { ComponentPropsWithoutRef, ReactNode } from 'react' +import React, { + ComponentPropsWithoutRef, + ForwardedRef, + forwardRef, + ReactNode, +} from 'react' type TDProps = Omit, 'children'> & { children?: ReactNode isBold?: boolean } -export default function TD({ - children, - className = '', - isBold = false, - ...props -}: TDProps) { +function TD( + { children, className = '', isBold = false, ...props }: TDProps, + ref: ForwardedRef +) { const style = `p-4 ${ isBold ? 'text-base-bold' : 'text-base-regular' } first:rounded-l-base last:rounded-r-base ${className}` return ( - + {children} ) } + +export default forwardRef(TD) diff --git a/components/ui/Table/TDLink.tsx b/components/ui/Table/TDLink.tsx index 4dbd21f46..735db60fc 100644 --- a/components/ui/Table/TDLink.tsx +++ b/components/ui/Table/TDLink.tsx @@ -1,35 +1,46 @@ import Link from 'next/link' -import React from 'react' +import React, { useEffect, useRef, useState } from 'react' import IconComponent, { IconName } from 'components/ui/IconComponent' import TD from 'components/ui/Table/TD' -import { unsafeRandomId } from 'utils/helpers' +import { getVisibleText, unsafeRandomId } from 'utils/helpers' export default function TDLink({ href, - label, + labelPrefix, className, }: { href: string - label: string + labelPrefix: string className?: string }) { + const tdRef = useRef(null) + const [label, setLabel] = useState(labelPrefix) const labelId = 'tdlink-icon-' + unsafeRandomId() + useEffect(() => { + const rowVisibleText = Array.from(tdRef.current!.parentElement!.children) + .slice(0, -1) + .map(getVisibleText) + .filter((cellVisibleText) => cellVisibleText !== null) + + setLabel(labelPrefix + ' ' + rowVisibleText.join(' ')) + }, [tdRef.current]) + // a11y card : https://kittygiraudel.com/2022/04/02/accessible-cards/ // absolute position in grandparent : https://stackoverflow.com/a/25768682 return ( - + diff --git a/styles/components/Modal.module.css b/styles/components/Modal.module.css index f9e7ccfdf..505a9a5be 100644 --- a/styles/components/Modal.module.css +++ b/styles/components/Modal.module.css @@ -1,6 +1,6 @@ .modalOverlay { position: fixed; - z-index: 10; + z-index: 100; left: 0; top: 0; width: 100%; diff --git a/tests/components/DetailMessageListeDeDiffusion.test.tsx b/tests/components/DetailMessageListeDeDiffusion.test.tsx index b4bd67027..c0f03a102 100644 --- a/tests/components/DetailMessageListeDeDiffusion.test.tsx +++ b/tests/components/DetailMessageListeDeDiffusion.test.tsx @@ -66,7 +66,7 @@ describe('DetailMessageListeDeDiffusion', () => { it('affiche l’heure du message', async () => { // Then - expect(screen.getByText('Envoyé à 14h00')).toBeInTheDocument() + expect(screen.getByText('Envoyé à 14:00')).toBeInTheDocument() }) it('affiche les destinataires du message', async () => { diff --git a/tests/components/TableauEvenementsConseiller.test.tsx b/tests/components/TableauEvenementsConseiller.test.tsx new file mode 100644 index 000000000..fca5d5baf --- /dev/null +++ b/tests/components/TableauEvenementsConseiller.test.tsx @@ -0,0 +1,68 @@ +import { screen } from '@testing-library/dom' +import { usePathname } from 'next/navigation' +import React from 'react' + +import TableauEvenementsConseiller from 'components/rdv/TableauEvenementsConseiller' +import { desEvenementsListItems } from 'fixtures/evenement' +import renderWithContexts from 'tests/renderWithContexts' + +describe('', () => { + beforeEach(async () => { + ;(usePathname as jest.Mock).mockReturnValue('/mes-jeunes') + }) + + describe('Quand il y a des rendez-vous', () => { + const listeRdv = desEvenementsListItems() + beforeEach(() => { + // When + renderWithContexts( + + ) + }) + + it('affiche les informations des rendez-vous', () => { + // Then + const rdv1 = listeRdv[0] + expect(screen.getByText(`${rdv1.labelBeneficiaires}`)).toBeInTheDocument() + expect(screen.getByText(rdv1.type)).toBeInTheDocument() + expect(screen.getByText(rdv1.modality!)).toBeInTheDocument() + expect( + screen.getByRole('cell', { + name: '21 octobre 2021 12 heure 0 durée 2 heure 5', + }) + ).toBeInTheDocument() + + const rdv2 = listeRdv[1] + expect(screen.getByText(`${rdv2.labelBeneficiaires}`)).toBeInTheDocument() + expect(screen.getByText(rdv2.type)).toBeInTheDocument() + expect(screen.getByText(rdv2.modality!)).toBeInTheDocument() + expect( + screen.getByRole('cell', { + name: '25 octobre 2021 14 heure 0 durée 25 minutes', + }) + ).toBeInTheDocument() + }) + + it('permet la modification des rendez-vous', () => { + expect( + screen.getByRole('link', { + name: 'Consulter l’événement du 21 octobre 2021 12:00 - 2h05 Jirac Kenji Autre par téléphone créé par Vous 1 inscrit', + }) + ).toHaveAttribute( + 'href', + '/mes-jeunes/edition-rdv?idRdv=' + listeRdv[0].id + ) + expect( + screen.getByRole('link', { + name: 'Consulter l’événement du 25 octobre 2021 14:00 - 25 min Jirac Raja Atelier En agence créé par -- 1 inscrit', + }) + ).toHaveAttribute( + 'href', + '/mes-jeunes/edition-rdv?idRdv=' + listeRdv[1].id + ) + }) + }) +}) diff --git a/tests/components/TableauRdvsBeneficiaire.test.tsx b/tests/components/TableauRdvsBeneficiaire.test.tsx index 428dd9129..22eaab7f0 100644 --- a/tests/components/TableauRdvsBeneficiaire.test.tsx +++ b/tests/components/TableauRdvsBeneficiaire.test.tsx @@ -1,15 +1,13 @@ import { screen } from '@testing-library/dom' -import { render, within } from '@testing-library/react' +import { act, render, within } from '@testing-library/react' import { DateTime } from 'luxon' import { usePathname } from 'next/navigation' import React from 'react' import TableauRdvsBeneficiaire from 'components/rdv/TableauRdvsBeneficiaire' -import { desEvenementsListItems } from 'fixtures/evenement' import { uneBaseBeneficiaire } from 'fixtures/beneficiaire' -import { EvenementListItem } from 'interfaces/evenement' -import { getNomBeneficiaireComplet } from 'interfaces/beneficiaire' -import { toShortDate } from 'utils/date' +import { desEvenementsListItems } from 'fixtures/evenement' +import { toFrenchDuration, toFrenchTime, toMonthday } from 'utils/date' describe('', () => { beforeEach(async () => { @@ -37,64 +35,76 @@ describe('', () => { }) describe('Quand il y a des rendez-vous', () => { - let listeRdv: EvenementListItem[] - beforeEach(() => { + const listeRdv = desEvenementsListItems() + beforeEach(async () => { // Given - listeRdv = desEvenementsListItems() // When - render( - - ) + await act(async () => { + render( + + ) + }) }) it('affiche les informations des rendez-vous', () => { // Then - listeRdv.forEach((rdv) => { - const date = DateTime.fromISO(rdv.date) - const horaires = `${toShortDate(date)} - ${date.toFormat( - "HH'h'mm" - )} - ${rdv.duree} min` - expect(screen.getByText(rdv.type)).toBeInTheDocument() - expect(screen.getByText(rdv.modality!)).toBeInTheDocument() - expect(screen.getByText(horaires)).toBeInTheDocument() - }) + const rdv1 = listeRdv[0] + const date1 = DateTime.fromISO(rdv1.date) + const horaires1 = `${toMonthday(date1)} - ${toFrenchTime(date1, { a11y: true })} - ${toFrenchDuration(rdv1.duree, { a11y: true })}` + expect(screen.getByRole('cell', { name: rdv1.type })).toBeInTheDocument() + expect( + screen.getByRole('cell', { name: rdv1.modality! }) + ).toBeInTheDocument() + expect(screen.getByRole('cell', { name: horaires1 })).toBeInTheDocument() + + // Then + const rdv2 = listeRdv[1] + const date2 = DateTime.fromISO(rdv2.date) + const horaires2 = `${toMonthday(date2)} - ${toFrenchTime(date2, { a11y: true })} - ${toFrenchDuration(rdv2.duree, { a11y: true })}` + expect( + screen.getByRole('cell', { name: 'Non modifiable ' + rdv2.type }) + ).toBeInTheDocument() + expect( + screen.getByRole('cell', { name: rdv2.modality! }) + ).toBeInTheDocument() + expect(screen.getByRole('cell', { name: horaires2 })).toBeInTheDocument() }) it('permet la modification des rendez-vous', () => { - listeRdv.forEach((rdv) => { - const link = screen.getByRole('link', { - name: `Consulter l’événement du ${DateTime.fromISO(rdv.date).toFormat( - 'EEEE d MMMM', - { locale: 'fr-FR' } - )} avec ${getNomBeneficiaireComplet(uneBaseBeneficiaire())}`, - }) - expect(link).toHaveAttribute( - 'href', - '/mes-jeunes/edition-rdv?idRdv=' + rdv.id - ) + const link1 = screen.getByRole('link', { + name: 'Consulter l’événement du 21/10/2021 - 12:00 - 2h05 Autre par téléphone oui', + }) + expect(link1).toHaveAttribute( + 'href', + '/mes-jeunes/edition-rdv?idRdv=' + listeRdv[0].id + ) + const link2 = screen.getByRole('link', { + name: 'Consulter l’événement du 25/10/2021 - 14:00 - 25 min Atelier En agence non', }) + expect(link2).toHaveAttribute( + 'href', + '/mes-jeunes/edition-rdv?idRdv=' + listeRdv[1].id + ) }) it('affiche si l’utilisateur est le créateur du rendez-vous', () => { const rdvsRows = screen.getAllByRole('row', { - name: new RegExp(`${listeRdv[0].labelBeneficiaires}`), + name: /Consulter l’événement du/, }) const rendezVous0 = rdvsRows[0] const rendezVous1 = rdvsRows[1] // Then - expect(within(rendezVous0).getByText('oui')).toHaveAttribute( - 'class', - 'sr-only' - ) - expect(within(rendezVous1).getByText('non')).toHaveAttribute( - 'class', - 'sr-only' - ) + expect( + within(rendezVous0).getByRole('cell', { name: 'oui' }) + ).toBeInTheDocument() + expect( + within(rendezVous1).getByRole('cell', { name: 'non' }) + ).toBeInTheDocument() }) }) }) diff --git a/tests/components/TableauRdvsConseiller.test.tsx b/tests/components/TableauRdvsConseiller.test.tsx deleted file mode 100644 index 711523619..000000000 --- a/tests/components/TableauRdvsConseiller.test.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { screen } from '@testing-library/dom' -import { DateTime } from 'luxon' -import { usePathname } from 'next/navigation' -import React from 'react' - -import TableauEvenementsConseiller from 'components/rdv/TableauEvenementsConseiller' -import { desEvenementsListItems } from 'fixtures/evenement' -import { EvenementListItem } from 'interfaces/evenement' -import renderWithContexts from 'tests/renderWithContexts' -import { toFrenchDuration, toFrenchTime, toLongMonthDate } from 'utils/date' - -describe('', () => { - beforeEach(async () => { - ;(usePathname as jest.Mock).mockReturnValue('/mes-jeunes') - }) - - describe('Quand il y a des rendez-vous', () => { - let listeRdv: EvenementListItem[] - beforeEach(() => { - // Given - listeRdv = desEvenementsListItems() - - // When - renderWithContexts( - - ) - }) - - it('affiche les informations des rendez-vous', () => { - // Then - listeRdv.forEach((rdv) => { - const horaires = `${toLongMonthDate(DateTime.fromISO(rdv.date))} ${toFrenchTime(rdv.date)} - durée ${toFrenchDuration( - rdv.duree, - { a11y: true } - )}` - - expect( - screen.getByText(`${rdv.labelBeneficiaires}`) - ).toBeInTheDocument() - expect(screen.getByText(rdv.type)).toBeInTheDocument() - expect(screen.getByText(rdv.modality!)).toBeInTheDocument() - expect(screen.getByRole('cell', { name: horaires })).toBeInTheDocument() - }) - }) - - it('permet la modification des rendez-vous', () => { - listeRdv.forEach((rdv) => { - const link = screen.getByRole('link', { - name: `Consulter l’événement du ${toLongMonthDate(DateTime.fromISO(rdv.date))} à ${toFrenchTime(rdv.date, { a11y: true })} avec ${rdv.labelBeneficiaires}`, - }) - expect(link).toHaveAttribute( - 'href', - '/mes-jeunes/edition-rdv?idRdv=' + rdv.id - ) - }) - }) - }) -}) diff --git a/tests/pages/EtablissementPage.test.tsx b/tests/pages/EtablissementPage.test.tsx index 4d7ffc0ae..96f4224b5 100644 --- a/tests/pages/EtablissementPage.test.tsx +++ b/tests/pages/EtablissementPage.test.tsx @@ -1,4 +1,4 @@ -import { act, screen, within } from '@testing-library/react' +import { act, screen, waitFor, within } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { AxeResults } from 'axe-core' import { axe } from 'jest-axe' @@ -143,7 +143,9 @@ describe('EtablissementPage client side', () => { const tableauDeBeneficiaires = screen.getByRole('table', { name: 'Résultat de recherche (1 éléments)', }) - expect(tableauDeBeneficiaires).toBeInTheDocument() + await waitFor(() => { + expect(tableauDeBeneficiaires).toBeInTheDocument() + }) expect( within(tableauDeBeneficiaires).getByRole('columnheader', { name: 'Bénéficiaire', @@ -166,7 +168,7 @@ describe('EtablissementPage client side', () => { ).toBeInTheDocument() expect( screen.getByRole('link', { - name: 'Accéder à la fiche de Page 1 Albert', + name: 'Accéder à la fiche de Page 1 Albert Emploi Le 01/03/2023 à 15:11 Carlo Le Calamar', }) ).toHaveAttribute('href', 'etablissement/beneficiaires/id-jeune') expect( diff --git a/tests/pages/FavorisPage.test.tsx b/tests/pages/FavorisPage.test.tsx index 043cc1556..c143cad55 100644 --- a/tests/pages/FavorisPage.test.tsx +++ b/tests/pages/FavorisPage.test.tsx @@ -49,7 +49,7 @@ describe('FavorisPage client side', () => { it('permet d’accéder à l’offre d’emploi', async () => { // Then const offre = screen.getByRole('link', { - name: 'Ouvrir l’offre offre 1', + name: 'Ouvrir l’offre offre 1 idOffre1 offre 1 organisation Offre d’emploi', }) expect(offre).toHaveAttribute('href', '/offres/emploi/idOffre1') @@ -58,7 +58,7 @@ describe('FavorisPage client side', () => { it('permet d’accéder à l’offre de service civique', async () => { // Then const offre = screen.getByRole('link', { - name: 'Ouvrir l’offre offre 2', + name: 'Ouvrir l’offre offre 2 idOffre2 offre 2 organisation Service civique', }) expect(offre).toHaveAttribute('href', '/offres/service-civique/idOffre2') @@ -67,7 +67,7 @@ describe('FavorisPage client side', () => { it('permet d’accéder à l’offre d’immersion', async () => { // Then const offre = screen.getByRole('link', { - name: 'Ouvrir l’offre offre 3', + name: 'Ouvrir l’offre offre 3 idOffre3 offre 3 organisation Immersion', }) expect(offre).toHaveAttribute('href', '/offres/immersion/idOffre3') @@ -76,7 +76,7 @@ describe('FavorisPage client side', () => { it('permet d’accéder à l’offre d’alternance', async () => { // Then const offre = screen.getByRole('link', { - name: 'Ouvrir l’offre offre 4', + name: 'Ouvrir l’offre offre 4 idOffre4 offre 4 organisation Alternance', }) expect(offre).toHaveAttribute('href', '/offres/alternance/idOffre4') diff --git a/tests/pages/ListesDiffusionPage.test.tsx b/tests/pages/ListesDiffusionPage.test.tsx index 188653b24..394d06958 100644 --- a/tests/pages/ListesDiffusionPage.test.tsx +++ b/tests/pages/ListesDiffusionPage.test.tsx @@ -115,7 +115,7 @@ describe('Page Listes de Diffusion', () => { listesDeDiffusion.forEach((liste) => { expect( screen.getByRole('link', { - name: 'Consulter la liste ' + liste.titre, + name: `Consulter la liste ${liste.titre} ${liste.beneficiaires.length} destinataire(s)`, }) ).toHaveAttribute( 'href', diff --git a/tests/pages/PortefeuillePage.test.tsx b/tests/pages/PortefeuillePage.test.tsx index fd16ae09d..299e45bc0 100644 --- a/tests/pages/PortefeuillePage.test.tsx +++ b/tests/pages/PortefeuillePage.test.tsx @@ -83,8 +83,9 @@ describe('PortefeuillePage client side', () => { jeunes.forEach((jeune) => { const nomBeneficiaire = `${jeune.nom} ${jeune.prenom}` const row = within( - screen.getByRole('cell', { name: new RegExp(nomBeneficiaire) }) - .parentElement! + screen.getByRole('cell', { + name: new RegExp('^Accéder.*' + nomBeneficiaire), + }).parentElement! ) if (jeune.dateFinCEJ) @@ -117,7 +118,7 @@ describe('PortefeuillePage client side', () => { //THEN expect( - within(row).getByRole('cell', { name: 'Le 07/12/2021 à 18h30' }) + within(row).getByRole('cell', { name: 'Le 07/12/2021 à 18:30' }) ).toBeInTheDocument() }) }) diff --git a/tests/pages/agenda/AgendaConseiller.page.test.tsx b/tests/pages/agenda/AgendaConseiller.page.test.tsx index e95f703bc..e8cec68c2 100644 --- a/tests/pages/agenda/AgendaConseiller.page.test.tsx +++ b/tests/pages/agenda/AgendaConseiller.page.test.tsx @@ -150,13 +150,13 @@ describe('Agenda - Onglet conseiller', () => { expect( screen.getByRole('link', { - name: 'Consulter l’événement du 1 septembre 2022 à 0 heure 0 avec Jirac Kenji', + name: 'Consulter l’événement du 1 septembre 2022 00:00 - 2h05 Jirac Kenji Autre par téléphone créé par Vous 1 inscrit', }) ).toBeInTheDocument() expect( screen.getByRole('link', { - name: 'Consulter l’événement du 7 septembre 2022 à 14 heure 59 avec Jirac Kenji', + name: 'Consulter l’événement du 7 septembre 2022 14:59 - 2h05 Jirac Kenji Autre par téléphone créé par Vous 2 inscrits', }) ).toBeInTheDocument() }) @@ -219,25 +219,25 @@ describe('Agenda - Onglet conseiller', () => { it('affiche le nombre d’inscrits', async () => { const row1 = screen .getByRole('cell', { - name: /1 septembre 2022 00h00 - durée 2 heure 5/, + name: /1 septembre 2022 0 heure 0 durée 2 heure 5/, }) .closest('tr')! const row2 = screen .getByRole('cell', { - name: /2 septembre 2022 00h00 - durée 2 heure 5/, + name: /2 septembre 2022 0 heure 0 durée 2 heure 5/, }) .closest('tr')! const row3 = screen .getByRole('cell', { - name: /3 septembre 2022 00h00 - durée 2 heure 5/, + name: /3 septembre 2022 0 heure 0 durée 2 heure 5/, }) .closest('tr')! const row4 = screen .getByRole('cell', { - name: /4 septembre 2022 00h00 - durée 2 heure 5/, + name: /4 septembre 2022 0 heure 0 durée 2 heure 5/, }) .closest('tr')! diff --git a/tests/pages/agenda/AgendaEtablissement.page.test.tsx b/tests/pages/agenda/AgendaEtablissement.page.test.tsx index 9456affe2..715cdf89d 100644 --- a/tests/pages/agenda/AgendaEtablissement.page.test.tsx +++ b/tests/pages/agenda/AgendaEtablissement.page.test.tsx @@ -152,7 +152,7 @@ describe('Agenda - Onglet établissement', () => { .closest('tr')! expect( within(row1).getByRole('cell', { - name: '29 août 2022 14h00 - durée 2 heure 5', + name: '29 août 2022 14 heure 0 durée 2 heure 5', }) ).toBeInTheDocument() expect( @@ -160,7 +160,7 @@ describe('Agenda - Onglet établissement', () => { ).toBeInTheDocument() expect( within(row1).getByRole('link', { - name: 'Consulter Atelier Prise de nouvelles par téléphone du lundi 29 août à 14h00', + name: 'Consulter Atelier du 29 août 2022 14:00 - 2h05 Prise de nouvelles par téléphone Atelier Visible 1 inscrit / 10 Clos', }) ).toBeInTheDocument() @@ -171,7 +171,7 @@ describe('Agenda - Onglet établissement', () => { .closest('tr')! expect( within(row2).getByRole('cell', { - name: '1 septembre 2022 14h00 - durée 30 minutes', + name: '1 septembre 2022 14 heure 0 durée 30 minutes', }) ).toBeInTheDocument() expect( @@ -179,13 +179,13 @@ describe('Agenda - Onglet établissement', () => { ).toBeInTheDocument() expect( within(row2).getByRole('link', { - name: 'Consulter Atelier Préparation de CV du jeudi 1 septembre à 14h00', + name: 'Consulter Atelier du 1 septembre 2022 14:00 - 30 min Préparation de CV Atelier Visible Complet À clore', }) ).toBeInTheDocument() expect( screen.getByRole('link', { - name: 'Consulter Atelier i-milo Titre offre session milo du dimanche 4 septembre à 14h00', + name: 'Consulter Atelier du 4 septembre 2022 14:00 - 2h05 Écriture de lettre de motivation Atelier Visible 1 inscrit / 10 À venir', }) ).toBeInTheDocument() }) @@ -380,7 +380,7 @@ describe('Agenda - Onglet établissement', () => { ).toBeInTheDocument() expect( screen.getByRole('link', { - name: 'Consulter Atelier i-milo Titre offre session milo du dimanche 4 septembre à 14h00', + name: 'Consulter Atelier du 4 septembre 2022 14:00 - 2h05 Écriture de lettre de motivation Atelier Visible 1 inscrit / 10 À venir', }) ).toBeInTheDocument() expect( @@ -390,7 +390,7 @@ describe('Agenda - Onglet établissement', () => { ).toBeInTheDocument() expect( screen.getByRole('link', { - name: 'Consulter Atelier i-milo 2 Titre offre session milo 2 du lundi 5 septembre à 14h00', + name: 'Consulter Atelier i-milo 2 du 5 septembre 2022 14:00 - 1h00 Titre offre session milo 2 Nom session Atelier i-milo 2 Non visible 1 inscrit / 10 À venir', }) ).toBeInTheDocument() }) diff --git a/tests/pages/edition-rdv/EditionRdvPage.test.tsx b/tests/pages/edition-rdv/EditionRdvPage.test.tsx index 289679488..76e2e93cd 100644 --- a/tests/pages/edition-rdv/EditionRdvPage.test.tsx +++ b/tests/pages/edition-rdv/EditionRdvPage.test.tsx @@ -902,7 +902,7 @@ describe('EditionRdvPage client side', () => { evenement.historique.slice(0, 2).forEach(({ date, auteur }) => { expect( getByTextContent( - `${DateTime.fromISO(date).toFormat("dd/MM/yyyy 'à' HH'h'mm")} : ${ + `${DateTime.fromISO(date).toFormat("dd/MM/yyyy 'à' HH':'mm")} : ${ auteur.prenom } ${auteur.nom}`, historique diff --git a/tests/pages/pilotage/PilotagePage.actions.test.tsx b/tests/pages/pilotage/PilotagePage.actions.test.tsx index 1c1ee6910..b94dbdb9d 100644 --- a/tests/pages/pilotage/PilotagePage.actions.test.tsx +++ b/tests/pages/pilotage/PilotagePage.actions.test.tsx @@ -8,13 +8,13 @@ import React from 'react' import Pilotage from 'app/(connected)/(with-sidebar)/(with-chat)/pilotage/PilotagePage' import { desCategories, uneListeDActionsAQualifier } from 'fixtures/action' -import { ActionPilotage } from 'interfaces/action' import { getActionsAQualifierClientSide, qualifierActions, } from 'services/actions.service' import getByDescriptionTerm from 'tests/querySelector' import renderWithContexts from 'tests/renderWithContexts' +import { toLongMonthDate } from 'utils/date' import { ApiError } from 'utils/httpClient' jest.mock('services/actions.service') @@ -22,22 +22,20 @@ jest.mock('components/ModalContainer') describe('PilotagePage client side - Actions', () => { describe('contenu', () => { - let actions: ActionPilotage[] - let actionSansCategorie: ActionPilotage + const actions = uneListeDActionsAQualifier() + const actionSansCategorie = { + id: '009347ea-4acb-4b61-9e08-b6caf38e2812', + titre: 'Regarder Tchoupi faire du tricycle', + beneficiaire: { + id: 'tchoupi', + nom: 'Trotro', + prenom: 'L’âne', + }, + dateFinReelle: '16/01/2024', + } let container: HTMLElement beforeEach(async () => { - actions = uneListeDActionsAQualifier() - actionSansCategorie = { - id: '009347ea-4acb-4b61-9e08-b6caf38e2812', - titre: 'Regarder Tchoupi faire du tricycle', - beneficiaire: { - id: 'tchoupi', - nom: 'Trotro', - prenom: 'L’âne', - }, - dateFinReelle: '16/01/2024', - } ;(getActionsAQualifierClientSide as jest.Mock).mockImplementation( async (_, { page, tri, filtres }) => ({ actions: [ @@ -159,7 +157,7 @@ describe('PilotagePage client side - Actions', () => { ).toBeInTheDocument() expect( screen.getByRole('link', { - name: `Accéder au détail de l’action terminée le ${dateFinReelle} : ${action.titre}`, + name: `Accéder au détail de l’action de ${action.beneficiaire.nom} ${action.beneficiaire.prenom} ${action.titre} ${action.categorie?.libelle} ${toLongMonthDate(action.dateFinReelle)}`, }) ).toHaveAttribute( 'href', diff --git a/tests/pages/pilotage/PilotagePage.animations-collectives.test.tsx b/tests/pages/pilotage/PilotagePage.animations-collectives.test.tsx index c0dbf5e15..8691dfa44 100644 --- a/tests/pages/pilotage/PilotagePage.animations-collectives.test.tsx +++ b/tests/pages/pilotage/PilotagePage.animations-collectives.test.tsx @@ -26,11 +26,10 @@ jest.mock('components/ModalContainer') describe('PilotagePage client side - Animations collectives', () => { describe('contenu', () => { - let animationsCollectives: AnimationCollectivePilotage[] + const animationsCollectives = uneListeDAnimationCollectiveAClore() let container: HTMLElement beforeEach(async () => { - animationsCollectives = uneListeDAnimationCollectiveAClore() ;( getAnimationsCollectivesACloreClientSide as jest.Mock ).mockImplementation(async (_, page) => ({ @@ -130,18 +129,24 @@ describe('PilotagePage client side - Animations collectives', () => { // Then animationsCollectives.forEach((animation) => { - const dateFormater = DateTime.fromISO(animation.date).toFormat( + const dateFormatee = DateTime.fromISO(animation.date).toFormat( 'dd MMMM yyyy', { locale: 'fr-FR' } ) - expect(within(tableau).getByText(dateFormater)).toBeInTheDocument() - expect(within(tableau).getByText(animation.titre)).toBeInTheDocument() expect( - within(tableau).getByText(`${animation.nombreInscrits}`) + within(tableau).getByRole('cell', { name: dateFormatee }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('cell', { name: animation.titre }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('cell', { + name: `${animation.nombreInscrits}`, + }) ).toBeInTheDocument() expect( within(tableau).getByRole('link', { - name: `Accéder au détail de l’animation collective : ${animation.titre}`, + name: `Accéder au détail de l’animation collective du ${dateFormatee} ${animation.titre} ${animation.nombreInscrits}`, }) ).toHaveAttribute( 'href', diff --git a/tests/pages/pilotage/PilotagePage.sessions.test.tsx b/tests/pages/pilotage/PilotagePage.sessions.test.tsx index e34d249d5..5a874d0af 100644 --- a/tests/pages/pilotage/PilotagePage.sessions.test.tsx +++ b/tests/pages/pilotage/PilotagePage.sessions.test.tsx @@ -20,10 +20,8 @@ jest.mock('services/sessions.service') describe('PilotagePage client side - Sessions', () => { describe('contenu', () => { let container: HTMLElement - let sessions: SessionsAClore[] - + const sessions = uneListeDeSessionsAClore() beforeEach(async () => { - sessions = uneListeDeSessionsAClore() ;(getSessionsACloreServerSide as jest.Mock).mockImplementation( async () => {} ) @@ -109,15 +107,50 @@ describe('PilotagePage client side - Sessions', () => { }) // Then - sessions.forEach((session) => { - expect(within(tableau).getByText(session.date)).toBeInTheDocument() - expect(within(tableau).getByText(session.titre)).toBeInTheDocument() - expect( - within(tableau).getByRole('link', { - name: `Accéder au détail de la session : ${session.titre}`, - }) - ).toHaveAttribute('href', '/agenda/sessions/' + session.id) - }) + const session1 = sessions[0] + expect( + within(tableau).getByRole('cell', { name: session1.date }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('cell', { + name: session1.titre + ' ' + session1.sousTitre, + }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('link', { + name: 'Accéder au détail de la session du 05/05/2023 Session 1 sous-titre de session 1', + }) + ).toHaveAttribute('href', '/agenda/sessions/' + session1.id) + + const session2 = sessions[1] + expect( + within(tableau).getByRole('cell', { name: session2.date }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('cell', { + name: session2.titre + ' ' + session2.sousTitre, + }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('link', { + name: 'Accéder au détail de la session du 06/05/2023 Session 2 sous-titre de session 2', + }) + ).toHaveAttribute('href', '/agenda/sessions/' + session2.id) + + const session3 = sessions[2] + expect( + within(tableau).getByRole('cell', { name: session3.date }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('cell', { + name: session3.titre + ' ' + session3.sousTitre, + }) + ).toBeInTheDocument() + expect( + within(tableau).getByRole('link', { + name: 'Accéder au détail de la session du 07/05/2023 Session 3 sous-titre de session 3', + }) + ).toHaveAttribute('href', '/agenda/sessions/' + session3.id) }) }) }) diff --git a/tests/services/agenda.service.test.ts b/tests/services/agenda.service.test.ts index 5616f922a..2952d5ae3 100644 --- a/tests/services/agenda.service.test.ts +++ b/tests/services/agenda.service.test.ts @@ -42,7 +42,7 @@ describe('AgendaService', () => { date: DateTime.fromISO('2021-10-20T10:00:00.000Z'), id: 'session-1', source: 'MILO', - titre: '12h00 - Offre de la session 1', + titre: '12:00 - Offre de la session 1', sousTitre: 'Workshop du 20 Octobre', type: 'session', typeSession: 'info coll i-milo', @@ -50,20 +50,20 @@ describe('AgendaService', () => { { id: '1', date: DateTime.fromISO('2021-10-21T10:00:00.000Z'), - titre: '12h00 - Prise de nouvelles par téléphone', + titre: '12:00 - Prise de nouvelles par téléphone', type: 'evenement', source: 'PASS_EMPLOI', }, { id: '1', date: DateTime.fromISO('2021-10-21T10:00:00.000Z'), - titre: '12h00 - Prise de nouvelles par téléphone', + titre: '12:00 - Prise de nouvelles par téléphone', type: 'evenement', source: 'PASS_EMPLOI', }, { id: 'session-2', - titre: '12h00 - Offre de la session 1', + titre: '12:00 - Offre de la session 1', sousTitre: 'Info coll du 21 Octobre', date: DateTime.fromISO('2021-10-21T10:00:00.000Z'), type: 'session', diff --git a/tests/utils/date.test.ts b/tests/utils/date.test.ts index 9b073418b..beb93b573 100644 --- a/tests/utils/date.test.ts +++ b/tests/utils/date.test.ts @@ -107,7 +107,7 @@ describe('dateUtils', () => { const uneDate = toRelativeDateTime(now.set({ hour: 13, minute: 12 })) //Then - expect(uneDate).toEqual('Aujourd’hui à 13h12') + expect(uneDate).toEqual('Aujourd’hui à 13:12') }) it(`formate la date d'hier`, () => { @@ -117,7 +117,7 @@ describe('dateUtils', () => { ) //Then - expect(uneDate).toEqual('Hier à 13h12') + expect(uneDate).toEqual('Hier à 13:12') }) it(`formate autre date`, () => { @@ -127,7 +127,7 @@ describe('dateUtils', () => { ) //Then - expect(uneDate).toEqual('Le 25/12/2018 à 13h12') + expect(uneDate).toEqual('Le 25/12/2018 à 13:12') }) }) }) diff --git a/utils/date.ts b/utils/date.ts index e42fde7f1..da0130d71 100644 --- a/utils/date.ts +++ b/utils/date.ts @@ -31,18 +31,18 @@ export function toWeekday(date: string | DateTime): string { return toFrenchFormat(date, WEEKDAY) } -const TIME_H_SEPARATOR = "HH'h'mm" -const TIME_A11Y_SEPARATOR = "H 'heure' m" +const TIME = "HH':'mm" +const TIME_A11Y = "H 'heure' m" /** 02h39 (a11y : 2 heure 39) */ export function toFrenchTime( date: string | DateTime, { a11y }: { a11y: boolean } = { a11y: false } ): string { - return toFrenchFormat(date, a11y ? TIME_A11Y_SEPARATOR : TIME_H_SEPARATOR) + return toFrenchFormat(date, a11y ? TIME_A11Y : TIME) } -const DATETIME_LONG = `dd/MM/yyyy 'à' ${TIME_H_SEPARATOR}` -const DATETIME_LONG_A11Y = `d MMMM yyyy 'à' ${TIME_A11Y_SEPARATOR}` +const DATETIME_LONG = `dd/MM/yyyy 'à' ${TIME}` +const DATETIME_LONG_A11Y = `d MMMM yyyy 'à' ${TIME_A11Y}` /** 02/06/2023 à 02h39 (a11y : 2 juin 2023 à 2h30) */ export function toFrenchDateTime( date: string | DateTime, @@ -52,7 +52,10 @@ export function toFrenchDateTime( return toFrenchFormat(date, DATETIME_LONG) } -export function toRelativeDateTime(date: string | DateTime): string { +export function toRelativeDateTime( + date: string | DateTime, + { a11y }: { a11y: boolean } = { a11y: false } +): string { if (!date) return '' const dateTime = date instanceof DateTime ? date : DateTime.fromISO(date) @@ -62,10 +65,10 @@ export function toRelativeDateTime(date: string | DateTime): string { } else if (dateIsYesterday(dateTime)) { dateString = 'Hier' } else { - dateString = `Le ${toShortDate(dateTime)}` + dateString = `Le ${a11y ? toLongMonthDate(dateTime) : toShortDate(dateTime)}` } - return `${dateString} à ${toFrenchTime(dateTime)}` + return `${dateString} à ${toFrenchTime(dateTime, { a11y })}` } export function compareDates( diff --git a/utils/helpers.ts b/utils/helpers.ts index 9c4fbb6f0..5d1ed7f47 100644 --- a/utils/helpers.ts +++ b/utils/helpers.ts @@ -23,3 +23,34 @@ export function redirectedFromHome(referer: string): boolean { export function unsafeRandomId(): string { return Math.random().toString().slice(2) } + +const TYPE_NODE_TEXT = 3 +const TYPE_NODE_ELEMENT = 1 +export function getVisibleText(nodes: Node | Node[]): string | null { + if (Object.prototype.hasOwnProperty.call(nodes, 'length')) + return ( + (nodes as Node[]) + .map(getVisibleText) + .filter((visibleText) => visibleText !== null) + .join(' ') + .trim() || null + ) + + const node = nodes as Node + if (node.nodeType === TYPE_NODE_TEXT) return node.nodeValue?.trim() || null + if (node.nodeType !== TYPE_NODE_ELEMENT) return null + + const element = node as Element + if (element.classList.contains('sr-only')) return null + if (element.nodeName.toUpperCase() === 'SVG') return null + + if (element.nodeName.toUpperCase() === 'SELECT') { + const selectedOptions = (element as HTMLSelectElement).selectedOptions + return getVisibleText(Array.from(selectedOptions)) + } + + if (element.hasChildNodes()) + return getVisibleText(Array.from(node.childNodes)) + + return null +}