Skip to content

Commit

Permalink
feat(services-jeunes): crée la page simple (#3307)
Browse files Browse the repository at this point in the history
* feat(services-jeunes): crée la page simple

* fix(a11y): corrige l'inclusion de l'intitulé du bouton dans le nom accessible
  • Loading branch information
sokl-octo authored Sep 12, 2024
1 parent 19adcf7 commit ccd7038
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export function ServicesJeunes(props: ServicesJeunesProps) {
<SeeMoreItemList
seeLessLabel="Voir moins de services"
seeMoreLabel="Voir plus de services"
seeLessAriaLabel={'Voir moins de résultats sur les services conçus pour les jeunes'}
seeMoreAriaLabel={'Voir plus de résultats sur les services conçus pour les jeunes'}
seeLessAriaLabel={'Voir moins de services conçus pour les jeunes'}
seeMoreAriaLabel={'Voir plus de services conçus pour les jeunes'}
numberOfVisibleItems={NUMBER_OF_VISIBLE_ITEMS}
itemList={cardListToDisplay} />
</Container>
Expand Down
6 changes: 3 additions & 3 deletions src/pages/espace-jeune/index.page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe('Page Espace Jeune', () => {
const mesuresJeunesSection = screen.getByRole('region', { name: 'les services jeunes' });

// THEN
const voirPlusDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir plus de résultats sur les services conçus pour les jeunes' });
const voirPlusDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir plus de services conçus pour les jeunes' });
expect(voirPlusDeServicesJeunesBouton).toBeVisible();
});

Expand All @@ -197,13 +197,13 @@ describe('Page Espace Jeune', () => {
</DependenciesProvider>,
);
const mesuresJeunesSection = screen.getByRole('region', { name: 'les services jeunes' });
const voirPlusDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir plus de résultats sur les services conçus pour les jeunes' });
const voirPlusDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir plus de services conçus pour les jeunes' });

// WHEN
await userEvent.click(voirPlusDeServicesJeunesBouton);

// THEN
const voirMoinsDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir moins de résultats sur les services conçus pour les jeunes' });
const voirMoinsDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir moins de services conçus pour les jeunes' });
expect(voirMoinsDeServicesJeunesBouton).toBeVisible();
});
});
Expand Down
10 changes: 10 additions & 0 deletions src/pages/services-jeunes/index.analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { PageTags } from '~/client/services/analytics/analytics';

const analyticsPageConfig: PageTags = {
page_template: 'contenu_liste_niv_1',
pagegroup: 'service_jeune_liste',
pagelabel: 'contenu_liste_niv_1',
'segment-site': 'contenu_liste',
};

export default analyticsPageConfig;
25 changes: 25 additions & 0 deletions src/pages/services-jeunes/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@use "@styles/utilities-deprecated";

.section {
padding-inline: 1rem;
margin-bottom: 3rem;
}

.cartesActualitesList {
display: flex;
gap: 2rem;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 2rem;
flex-direction: column;
}

.carteActualite {
@include utilities-deprecated.media(medium) {
width: 22.5rem;
}
}

.carteActualiteDescription {
@include utilities-deprecated.line-clamp(3);
}
214 changes: 214 additions & 0 deletions src/pages/services-jeunes/index.page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/**
* @jest-environment jsdom
*/
import '~/test-utils';

import { render, screen, within } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';

import { mockUseRouter } from '~/client/components/useRouter.mock';
import { mockScrollIntoView, mockSmallScreen } from '~/client/components/window.mock';
import { DependenciesProvider } from '~/client/context/dependenciesContainer.context';
import { aManualAnalyticsService } from '~/client/services/analytics/analytics.service.fixture';
import ServicesJeunePage, { getStaticProps } from '~/pages/services-jeunes/index.page';
import { createFailure, createSuccess } from '~/server/errors/either';
import { ErreurMetier } from '~/server/errors/erreurMetier.types';
import { aServiceJeune, aServiceJeuneList } from '~/server/services-jeunes/domain/servicesJeunes.fixture';
import { dependencies } from '~/server/start';


jest.mock('~/server/start', () => ({
dependencies: {
cmsDependencies: {
duréeDeValiditéEnSecondes: jest.fn(),
},
servicesJeunesDependencies: {
consulterLesServicesJeunesUseCase: {
handle: jest.fn(),
},
},
},
}));

describe('Page Services Jeunes', () => {
beforeEach(() => {
mockSmallScreen();
mockUseRouter({});
mockScrollIntoView();
});
afterEach(() => {
jest.clearAllMocks();
});

it('lorsque le feature flip old espace jeune est actif, redirige vers la page 404', async () => {
// Given
process.env.NEXT_PUBLIC_OLD_ESPACE_JEUNE_FEATURE = '1';

// When
const result = await getStaticProps();

// Then
expect(result).toEqual({ notFound: true });
});
describe('lorsque le feature flip old espace jeune est désactivé', () => {
beforeEach(() => {
process.env.NEXT_PUBLIC_OLD_ESPACE_JEUNE_FEATURE = '0';
});

it('doit rendre du HTML respectant la specification', () => {
// Given
const serviceJeuneList = aServiceJeuneList();
mockUseRouter({});
mockSmallScreen();

// When
const { container } = render(<DependenciesProvider analyticsService={aManualAnalyticsService()}>
<ServicesJeunePage serviceJeuneList={serviceJeuneList} />
</DependenciesProvider>);

// Then
expect(container.outerHTML).toHTMLValidate();
});
it('n‘a pas de défaut d‘accessibilité', async () => {
// Given
const serviceJeuneList = aServiceJeuneList();
mockUseRouter({});
mockSmallScreen();

// When
const { container } = render(
<DependenciesProvider
analyticsService={aManualAnalyticsService()}>
<ServicesJeunePage
serviceJeuneList={serviceJeuneList} />);
</DependenciesProvider>);

// Then
await expect(container).toBeAccessible();
});
it('envoie les analytics de la page à son affichage', () => {
// Given
const serviceJeuneList = aServiceJeuneList();
const analyticsService = aManualAnalyticsService();

// When
render(
<DependenciesProvider
analyticsService={analyticsService}>
<ServicesJeunePage serviceJeuneList={serviceJeuneList} />
</DependenciesProvider>,
);

// Then
expect(analyticsService.envoyerAnalyticsPageVue).toHaveBeenCalledWith({
page_template: 'contenu_liste_niv_1',
pagegroup: 'service_jeune_liste',
pagelabel: 'contenu_liste_niv_1',
'segment-site': 'contenu_liste',
});
});

it('appelle le serveur pour récupérer les actualités', async () => {
// Given
jest.spyOn(dependencies.servicesJeunesDependencies.consulterLesServicesJeunesUseCase, 'handle').mockResolvedValue(createSuccess(aServiceJeuneList()));

// When
await getStaticProps();

// Then
expect(dependencies.servicesJeunesDependencies.consulterLesServicesJeunesUseCase.handle).toHaveBeenCalledTimes(1);
});

it('quand le service est indisponible, retourne une 404', async () => {
// Given
jest.spyOn(dependencies.servicesJeunesDependencies.consulterLesServicesJeunesUseCase, 'handle').mockResolvedValue(createFailure(ErreurMetier.SERVICE_INDISPONIBLE));

// When
const result = await getStaticProps();

// Then
expect(result).toEqual({ notFound: true, revalidate: 1 });
});

describe('Si des services jeunes sont récupérés', () => {
it('affiche au maximum 6 services initialement', () => {
// Given
const serviceJeuneList = [
aServiceJeune({ titre: 'service 1' }),
aServiceJeune({ titre: 'service 2' }),
aServiceJeune({ titre: 'service 3' }),
aServiceJeune({ titre: 'service 4' }),
aServiceJeune({ titre: 'service 5' }),
aServiceJeune({ titre: 'service 6' }),
aServiceJeune({ titre: 'service 7' }),
];
const analyticsService = aManualAnalyticsService();

// When
render(
<DependenciesProvider analyticsService={analyticsService}>
<ServicesJeunePage serviceJeuneList={serviceJeuneList} />
</DependenciesProvider>,
);

// Then
const mesuresJeunesSection = screen.getByRole('region', { name: 'les services jeunes' });
const servicesJeunesList = within(mesuresJeunesSection).getAllByRole('listitem');
expect(servicesJeunesList.length).toBe(6);
});
it('affiche un bouton voir plus quand il y a plus de 6 services', () => {
// Given
const serviceJeuneList = [
aServiceJeune({ titre: 'service 1' }),
aServiceJeune({ titre: 'service 2' }),
aServiceJeune({ titre: 'service 3' }),
aServiceJeune({ titre: 'service 4' }),
aServiceJeune({ titre: 'service 5' }),
aServiceJeune({ titre: 'service 6' }),
aServiceJeune({ titre: 'service 7' }),
];
const analyticsService = aManualAnalyticsService();

// When
render(
<DependenciesProvider analyticsService={analyticsService}>
<ServicesJeunePage serviceJeuneList={serviceJeuneList} />
</DependenciesProvider>,
);

// Then
const mesuresJeunesSection = screen.getByRole('region', { name: 'les services jeunes' });
const voirPlusDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir plus de services conçus pour les jeunes' });
expect(voirPlusDeServicesJeunesBouton).toBeVisible();
});
it('affiche un bouton voir moins quand plus de 6 services jeunes sont visibles', async () => {
// Given
const serviceJeuneList = [
aServiceJeune({ titre: 'service 1' }),
aServiceJeune({ titre: 'service 2' }),
aServiceJeune({ titre: 'service 3' }),
aServiceJeune({ titre: 'service 4' }),
aServiceJeune({ titre: 'service 5' }),
aServiceJeune({ titre: 'service 6' }),
aServiceJeune({ titre: 'service 7' }),
];
const analyticsService = aManualAnalyticsService();

render(
<DependenciesProvider analyticsService={analyticsService}>
<ServicesJeunePage serviceJeuneList={serviceJeuneList} />
</DependenciesProvider>,
);
const mesuresJeunesSection = screen.getByRole('region', { name: 'les services jeunes' });
const voirPlusDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir plus de services conçus pour les jeunes' });

// When
await userEvent.click(voirPlusDeServicesJeunesBouton);

// Then
const voirMoinsDeServicesJeunesBouton = within(mesuresJeunesSection).getByRole('button', { name: 'Voir moins de services conçus pour les jeunes' });
expect(voirMoinsDeServicesJeunesBouton).toBeVisible();
});
});
});
});
63 changes: 63 additions & 0 deletions src/pages/services-jeunes/index.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { GetStaticPropsResult } from 'next';
import React from 'react';

import { ServicesJeunes } from '~/client/components/features/ServicesJeunes/ServicesJeunes';
import { Head } from '~/client/components/head/Head';
import { LightHero, LightHeroPrimaryText, LightHeroSecondaryText } from '~/client/components/ui/Hero/LightHero';
import useAnalytics from '~/client/hooks/useAnalytics';
import analytics from '~/pages/espace-jeune/index.analytics';
import { isFailure } from '~/server/errors/either';
import { ServiceJeune } from '~/server/services-jeunes/domain/servicesJeunes';
import { dependencies } from '~/server/start';

import styles from './index.module.scss';

interface ServicesJeunePageProps {
serviceJeuneList: Array<ServiceJeune>
}

export default function ServicesJeunesPage({ serviceJeuneList }: ServicesJeunePageProps) {
useAnalytics(analytics);

return (
<>
<Head
title="Services jeunes | 1jeune1solution"
robots="index,follow" />
<main id="contenu">
<LightHero>
<h2>
<LightHeroPrimaryText>Services jeunes, retrouvez les services conçus pour vous :</LightHeroPrimaryText>
<LightHeroSecondaryText>
entrée dans la vie professionnelle, orientation, formation, accompagnement, logement, aides et outils
</LightHeroSecondaryText>
</h2>
</LightHero>
<section className={styles.section} aria-label="les services jeunes">
<ServicesJeunes cardList={serviceJeuneList} />
</section>
</main>
</>
);
}

export async function getStaticProps(): Promise<GetStaticPropsResult<ServicesJeunePageProps>> {
const isServicesJeunesVisible = process.env.NEXT_PUBLIC_OLD_ESPACE_JEUNE_FEATURE === '0';
if (!isServicesJeunesVisible) {
return { notFound: true };
}

const serviceJeuneList = await dependencies.servicesJeunesDependencies.consulterLesServicesJeunesUseCase.handle();

if (isFailure(serviceJeuneList)) {
return { notFound: true, revalidate: 1 };
}

return {
props: {
serviceJeuneList: JSON.parse(JSON.stringify(serviceJeuneList.result)),
},
revalidate: dependencies.cmsDependencies.duréeDeValiditéEnSecondes(),
};
}

0 comments on commit ccd7038

Please sign in to comment.