Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(a11y): utiliser le select sur les pages Meilisearch #3147

Merged
merged 6 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cypress/e2e/stage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ describe('Recherche de stages', () => {
cy.intercept({ pathname: '/multi-search' }, stageNonFiltreeResponse).as('facets');
cy.wait('@facets');

// FIXME (GAFI 06-11-2023): Devrait être role combobox
cy.findByRole('button', { name: /Domaines/i }).click();
cy.findByRole('combobox', { name: /Domaines/i }).click();

cy.findAllByRole('option').first().should('contain.text', 'Achats');
cy.findAllByRole('option').eq(1).should('contain.text', 'Production');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import React from 'react';

import styles
from '~/client/components/features/Evenement/FormulaireRecherche/FormulaireRechercheEvenement.module.scss';
import { MeilisearchComboboxLocalisation } from '~/client/components/ui/Meilisearch/MeilisearchComboboxLocalisation';
import { MeilisearchCustomSearchBox } from '~/client/components/ui/Meilisearch/MeilisearchCustomSearchBox';
import { MeilisearchComboboxLocalisation } from '~/client/components/ui/Meilisearch/MeilisearchComboboxLocalisation/MeilisearchComboboxLocalisation';
import { MeilisearchInput } from '~/client/components/ui/Meilisearch/MeilisearchInput/MeilisearchInput';

const LIMIT_MAX_FACETS = 10000;

export function FormulaireRechercheEvenement() {
return (
<form className={styles.rechercherEvenementForm} onSubmit={(event) => event.preventDefault()}>
<MeilisearchCustomSearchBox
<MeilisearchInput
label="Mot-clé, métier, accompagnement…"
name="motCle"
placeholder="Exemples : gendarmerie, cuisinier, mentorat"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { SearchResults } from 'algoliasearch-helper';
import { SortBy } from 'instantsearch.js/es/types';

import styles from '~/client/components/features/FicheMétier/FormulaireRecherche/FormulaireRechercheFicheMetier.module.scss';
import { MeilisearchCustomRefinementList } from '~/client/components/ui/Meilisearch/MeilisearchCustomRefinementList';
import { MeilisearchCustomSearchBox } from '~/client/components/ui/Meilisearch/MeilisearchCustomSearchBox';
import styles
from '~/client/components/features/FicheMétier/FormulaireRecherche/FormulaireRechercheFicheMetier.module.scss';
import { MeilisearchInput } from '~/client/components/ui/Meilisearch/MeilisearchInput/MeilisearchInput';
import { MeilisearchSelectMultiple } from '~/client/components/ui/Meilisearch/MeilisearchSelectMultiple/MeilisearchSelectMultiple';

const MEILISEARCH_SORT_BY_LABEL_ASC: SortBy<SearchResults.FacetValue> = ['name:asc'];

export function FormulaireRechercheFicheMetier() {
return (
<form className={styles.RechercherMetierForm} onSubmit={(event) => event.preventDefault()}>
<MeilisearchCustomSearchBox
<MeilisearchInput
className={styles.inputNomMetier}
label="Métier"
name="metier"
placeholder="Exemple : cuisinier"
/>
<MeilisearchCustomRefinementList
/>
<MeilisearchSelectMultiple
className={styles.inputCentresInteret}
attribute="centres_interet"
limit={100}
label="Centres d‘intérêt"
sortBy={MEILISEARCH_SORT_BY_LABEL_ASC}
/>
/>
</form>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,79 +10,37 @@ import {
import {
generateRefinementListItem,
mockUseRefinementList,
} from '~/client/components/ui/Meilisearch/tests/mockMeilisearchUseFunctions';
} from '~/client/components/ui/Meilisearch/mockMeilisearchUseFunctions';
import { mockLargeScreen, mockSmallScreen } from '~/client/components/window.mock';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const spyed = jest.spyOn(require('react-instantsearch'), 'useRefinementList');

let refineMock: jest.Mock<string>;

describe('FormulaireRechercheAnnonceLogement', () => {
describe('en Desktop', () => {
beforeEach(() => {
mockLargeScreen();
});
beforeEach(() => {
// GIVEN
refineMock = jest.fn();
spyed.mockImplementation(() => mockUseRefinementList({
items: [ generateRefinementListItem({ label: 'exemple', value: 'exemple' }) ],
refine: refineMock,
}));
});

afterEach(() => {
jest.clearAllMocks();
});
it('affiche un formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

it('affiche un formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const form = screen.getByRole('search');
expect(form).toBeInTheDocument();
});

it('n‘affiche pas de bouton pour filtrer la recherche', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonFiltreMobile = screen.getByTestId('bouton-filtrer-recherche-mobile');
expect(buttonFiltreMobile).toBeInTheDocument();
});

it('affiche le champ ville dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const inputVille = screen.getByRole('textbox', { name: 'Ville' });
expect(inputVille).toBeInTheDocument();
});

it('affiche le champ type d‘offre dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonTypeOffre = screen.getByRole('button', { name: 'Type d‘offre' });
expect(buttonTypeOffre).toBeInTheDocument();
});

it('affiche le champ type de bien dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonTypeOffre = screen.getByRole('button', { name: 'Type de bien' });
expect(buttonTypeOffre).toBeInTheDocument();
});

it('affiche le champ prix dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);
const form = screen.getByRole('search');
expect(form).toBeVisible();
});

const buttonPrix = screen.getByRole('button', { name: 'Prix' });
expect(buttonPrix).toBeInTheDocument();
});
beforeEach(() => {
mockLargeScreen();
spyed.mockImplementation(() => mockUseRefinementList({
items: [generateRefinementListItem({ label: 'exemple', value: 'exemple' })],
refine: jest.fn(),
}));
});

it('affiche le champ surface dans le formulaire', () => {
describe('en Desktop', () => {
it('affiche les champs de recherche', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonSurface = screen.getByRole('button', { name: 'Surface (m²)' });
expect(buttonSurface).toBeInTheDocument();
expect(screen.getByRole('textbox', { name: 'Ville' })).toBeVisible();
expect(screen.getByRole('combobox', { name: 'Type d‘offre' })).toBeVisible();
expect(screen.getByRole('combobox', { name: 'Type de bien' })).toBeVisible();
expect(screen.getByRole('button', { name: 'Surface (m²)' })).toBeVisible();
expect(screen.getByRole('button', { name: 'Prix' })).toBeVisible();
});
});

Expand All @@ -91,60 +49,17 @@ describe('FormulaireRechercheAnnonceLogement', () => {
mockSmallScreen();
});

afterEach(() => {
jest.clearAllMocks();
});

it('affiche un formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const form = screen.getByRole('search');
expect(form).toBeInTheDocument();
});

it('affiche le champ ville dans le formulaire', () => {
it('affiche uniquement le champ ville dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const inputVille = screen.getByRole('textbox', { name: 'Ville' });
expect(inputVille).toBeInTheDocument();
expect(inputVille).toBeVisible();
expect(screen.getByRole('textbox', { name: 'Ville' })).toBeVisible();
});

it('affiche un bouton pour filtrer la recherche', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonFiltre = screen.getByRole('button', { name: 'Filtrer ma recherche' });
expect(buttonFiltre).toBeInTheDocument();
});

it('n‘affiche pas le champ type d‘offre dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonTypeOffreDesktop = screen.getByTestId('input-type-offre-desktop');
expect(buttonTypeOffreDesktop).toBeInTheDocument();

});

it('n‘affiche pas le champ type de bien dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonTypeBienDesktop = screen.getByTestId('input-type-bien-desktop');
expect(buttonTypeBienDesktop).toBeInTheDocument();

});

it('n‘affiche pas le champ prix dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonPrixDesktop = screen.getByTestId('input-prix-desktop');
expect(buttonPrixDesktop).toBeInTheDocument();
});

it('n‘affiche pas le champ surface dans le formulaire', () => {
render(<FormulaireRechercheAnnonceLogement/>);

const buttonSurfaceDesktop = screen.getByTestId('input-surface-desktop');
expect(buttonSurfaceDesktop).toBeInTheDocument();
expect(buttonFiltre).toBeVisible();
});

describe('quand l‘utilisateur ouvre les filtres de recherche', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import styles
import { ButtonComponent } from '~/client/components/ui/Button/ButtonComponent';
import { FilterAccordion } from '~/client/components/ui/FilterAccordion/FilterAccordion';
import { Icon } from '~/client/components/ui/Icon/Icon';
import { MeilisearchCustomRangeInput } from '~/client/components/ui/Meilisearch/MeilisearchCustomRangeInput';
import {
MeilisearchCustomRangeInputForModal,
} from '~/client/components/ui/Meilisearch/MeilisearchCustomRangeInputForModal';
import { MeilisearchCustomRefinementList } from '~/client/components/ui/Meilisearch/MeilisearchCustomRefinementList';
MeilisearchCheckboxList,
} from '~/client/components/ui/Meilisearch/MeilisearchCheckboxList/MeilisearchCheckboxList';
import { MeilisearchInput } from '~/client/components/ui/Meilisearch/MeilisearchInput/MeilisearchInput';
import { MeilisearchRange } from '~/client/components/ui/Meilisearch/MeilisearchRange/MeilisearchRange';
import {
MeilisearchCustomRefinementListForModal,
} from '~/client/components/ui/Meilisearch/MeilisearchCustomRefinementListForModal';
import { MeilisearchCustomSearchBox } from '~/client/components/ui/Meilisearch/MeilisearchCustomSearchBox';
MeilisearchRangeForModal,
} from '~/client/components/ui/Meilisearch/MeilisearchRange/MeilisearchRangeForModal';
import { MeilisearchSelectMultiple } from '~/client/components/ui/Meilisearch/MeilisearchSelectMultiple/MeilisearchSelectMultiple';
import { ModalComponent } from '~/client/components/ui/Modal/ModalComponent';

export const PRIX_MINIMUM = 0;
Expand All @@ -31,45 +31,41 @@ export function FormulaireRechercheAnnonceLogement() {
className={styles.RechercherLogementForm}
role="search"
onSubmit={(event) => event.preventDefault()}>
<MeilisearchCustomSearchBox
<MeilisearchInput
className={styles.inputVille}
label="Ville"
name="ville"
placeholder="Exemples : Paris, Toulouse"
/>
<MeilisearchCustomRefinementList
<MeilisearchSelectMultiple
className={styles.filtresDesktop}
attribute="type"
label="Type d‘offre"
sortBy={['name:asc']}
data-testid="input-type-offre-desktop"
/>
<MeilisearchCustomRefinementList
<MeilisearchSelectMultiple
className={styles.filtresDesktop}
attribute="typeBien"
label="Type de bien"
sortBy={['name:asc']}
data-testid="input-type-bien-desktop"
/>
<MeilisearchCustomRangeInput
<MeilisearchRange
className={styles.filtresDesktop}
attribute="surface"
label="Surface (m²)"
placeholder="Surface"
unite={UNITE_SURFACE}
min={SURFACE_MINIMUM}
max={SURFACE_MAXIMUM}
data-testid="input-surface-desktop"
/>
<MeilisearchCustomRangeInput
<MeilisearchRange
className={styles.filtresDesktop}
attribute="prix"
label="Prix"
placeholder="Fourchette de prix"
unite={DEVISE}
min={PRIX_MINIMUM}
max={PRIX_MAXIMUM}
data-testid="input-prix-desktop"
/>
<div className={styles.filtresAvancesMobile}>
<ButtonComponent
Expand All @@ -78,7 +74,6 @@ export function FormulaireRechercheAnnonceLogement() {
icon={<Icon name="filter"/>}
iconPosition="right"
label="Filtrer ma recherche"
data-testid="bouton-filtrer-recherche-mobile"
onClick={() => setIsFiltresAvancésMobileOpen(true)}
/>
<ModalComponent
Expand All @@ -94,29 +89,29 @@ export function FormulaireRechercheAnnonceLogement() {
</ModalComponent.Title>
<ModalComponent.Content className={styles.filtresAvancésModalContenu}>
<FilterAccordion title="Type d‘offre" open>
<MeilisearchCustomRefinementListForModal
<MeilisearchCheckboxList
attribute="type"
label="Type d‘offre"
sortBy={['name:asc']}
/>
</FilterAccordion>
<FilterAccordion title="Type de bien">
<MeilisearchCustomRefinementListForModal
<MeilisearchCheckboxList
attribute="typeBien"
label="Type de bien"
sortBy={['name:asc']}
/>
</FilterAccordion>
<FilterAccordion title="Prix">
<MeilisearchCustomRangeInputForModal
<MeilisearchRangeForModal
attribute="prix"
unite="€"
min={PRIX_MINIMUM}
max={PRIX_MAXIMUM}
/>
</FilterAccordion>
<FilterAccordion title="Surface">
<MeilisearchCustomRangeInputForModal
<MeilisearchRangeForModal
attribute="surface"
unite="m²"
min={SURFACE_MINIMUM}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import React from 'react';

import styles
from '~/client/components/features/OffreDeStage/FormulaireRecherche/FormulaireRechercheOffreStage.module.scss';
import { MeilisearchComboboxLocalisation } from '~/client/components/ui/Meilisearch/MeilisearchComboboxLocalisation';
import { MeilisearchCustomRefinementList } from '~/client/components/ui/Meilisearch/MeilisearchCustomRefinementList';
import { MeilisearchCustomSearchBox } from '~/client/components/ui/Meilisearch/MeilisearchCustomSearchBox';
import { MeilisearchComboboxLocalisation } from '~/client/components/ui/Meilisearch/MeilisearchComboboxLocalisation/MeilisearchComboboxLocalisation';
import { MeilisearchInput } from '~/client/components/ui/Meilisearch/MeilisearchInput/MeilisearchInput';
import { MeilisearchSelectMultiple } from '~/client/components/ui/Meilisearch/MeilisearchSelectMultiple/MeilisearchSelectMultiple';
import { DomainesStage } from '~/server/stages/repository/domainesStage';

const LIMIT_MAX_FACETS = 100000;
Expand Down Expand Up @@ -44,7 +44,7 @@ export function sortByDurationAscending(a: SearchResults.FacetValue, b: SearchRe
export function FormulaireRechercheOffreStage() {
return (
<form className={styles.RechercherStageForm} onSubmit={(event) => event.preventDefault()}>
<MeilisearchCustomSearchBox
<MeilisearchInput
label="Métiers, mots clés, …"
name="motCle"
placeholder="Exemples : designer, juriste…"
Expand All @@ -53,13 +53,13 @@ export function FormulaireRechercheOffreStage() {
attribute="localisationFiltree"
limit={LIMIT_MAX_FACETS}
/>
<MeilisearchCustomRefinementList
<MeilisearchSelectMultiple
attribute="domaines"
limit={LIMIT_MAX_DOMAINS}
label="Domaines"
sortBy={sortWithNonRenseigneAtTheEnd}
/>
<MeilisearchCustomRefinementList
<MeilisearchSelectMultiple
attribute="dureeCategorisee"
label="Durée de stage"
sortBy={sortByDurationAscending}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { render, screen } from '@testing-library/react';

import { InstantSearchErrorBoundary } from '~/client/components/layouts/InstantSearch/InstantSearchErrorBoundary';
import { mockUseInstantSearch } from '~/client/components/ui/Meilisearch/tests/mockMeilisearchUseFunctions';
import { mockUseInstantSearch } from '~/client/components/ui/Meilisearch/mockMeilisearchUseFunctions';
import { mockUseRouter } from '~/client/components/useRouter.mock';
import { mockLargeScreen } from '~/client/components/window.mock';
// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down
Loading