Séparer les absences par état
Le calendrier portait tout : les demandes en attente, les décisions rendues et celles qui avaient expiré, distinguées par un simple badge. Une file d'attente se lit mal dans un calendrier — elle se lit par ancienneté, et le calendrier range par date d'absence. Quatre routes désormais : le calendrier, la file à traiter, les traitées et les expirées. Le calendrier a déménagé sous /absences plutôt que d'être dupliqué, et /conges redirige en conservant le mois : un lien partagé dans un message continue d'ouvrir la bonne page. Les trois files partagent une requête et un rendu. C'est délibéré : la règle qui masque le motif d'une absence Sécurité sociale vaut pour les trois, et trois copies de cette règle garantiraient qu'une finisse par diverger. Une donnée de santé qui ne fuit que sur l'écran « traitées » reste une fuite. La file à traiter classe par ancienneté de demande, les files closes par date d'absence décroissante : on cherche d'un côté ce qui attend depuis trop longtemps, de l'autre ce qui vient d'être décidé. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
527ea2e78a
commit
98b289784a
14 files changed
+811
-351
No files matched your search
@@ -55,7 +55,7 @@ function nextWeekday(weekday: number): string {
|
||||
* attente » et « acceptée » bloquent.
|
||||
*/
|
||||
async function release(page: Page, marker: string, month?: string) {
|
||||
await page.goto(month ? `/conges?mois=${month}` : '/conges');
|
||||
await page.goto(month ? `/absences/calendrier?mois=${month}` : '/absences/calendrier');
|
||||
|
||||
const pending = page
|
||||
.locator('section')
|
||||
@@ -117,7 +117,7 @@ async function request(
|
||||
test('le formulaire nomme le dernier jour d’absence, pas la date de fin', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
// Le libellé exact coûte moins cher qu'une régularisation de solde.
|
||||
await expect(
|
||||
page.getByText('Dernier jour d’absence', { exact: true }),
|
||||
@@ -128,7 +128,7 @@ test('le formulaire nomme le dernier jour d’absence, pas la date de fin', asyn
|
||||
});
|
||||
|
||||
test('une demande apparaît dans la file, puis se décide', async ({ page }) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
|
||||
const from = isoDate(0);
|
||||
const to = isoDate(4);
|
||||
@@ -160,7 +160,7 @@ test('une demande apparaît dans la file, puis se décide', async ({ page }) =>
|
||||
// La ligne est visée par **ses** dates, pas par « la première de ce
|
||||
// salarié » : les passages précédents en laissent d'autres dans le même
|
||||
// mois, et certaines n'offrent plus de bouton d'annulation.
|
||||
await page.goto(`/conges?mois=${from.slice(0, 7)}`);
|
||||
await page.goto(`/absences/calendrier?mois=${from.slice(0, 7)}`);
|
||||
const accepted = page
|
||||
.locator('section')
|
||||
.filter({ hasText: 'Absences du mois' })
|
||||
@@ -173,7 +173,7 @@ test('une demande apparaît dans la file, puis se décide', async ({ page }) =>
|
||||
});
|
||||
|
||||
test('deux absences qui se recouvrent sont refusées', async ({ page }) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
|
||||
await release(page, 'Chevauchement ');
|
||||
|
||||
@@ -208,7 +208,7 @@ test('deux absences qui se recouvrent sont refusées', async ({ page }) => {
|
||||
});
|
||||
|
||||
test('une période sans jour décomptable est refusée', async ({ page }) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
|
||||
// Un dimanche seul : jamais ouvrable, donc rien à décompter.
|
||||
const sunday = nextWeekday(0);
|
||||
@@ -222,7 +222,7 @@ test('une période sans jour décomptable est refusée', async ({ page }) => {
|
||||
});
|
||||
|
||||
test('un jour férié dans la période n’est pas décompté', async ({ page }) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
|
||||
// Un jour férié pris au hasard parmi ceux de l'année : la période qui
|
||||
// l'englobe ne doit pas le décompter, et l'utilisateur n'a pas eu à scinder
|
||||
@@ -263,7 +263,7 @@ test('un jour férié dans la période n’est pas décompté', async ({ page })
|
||||
test('une date de fin antérieure au début rappelle la règle', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
|
||||
const form = await request(page, {
|
||||
from: isoDate(22),
|
||||
@@ -277,7 +277,7 @@ test('une date de fin antérieure au début rappelle la règle', async ({
|
||||
});
|
||||
|
||||
test('le solde revient à son niveau après un aller-retour', async ({ page }) => {
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
|
||||
const counters = page.locator('section').filter({ hasText: 'Compteurs' });
|
||||
await expect(counters).toBeVisible();
|
||||
|
||||
@@ -52,7 +52,7 @@ test('une entrée de navigation non construite mène à un écran explicite', as
|
||||
page,
|
||||
}) => {
|
||||
// La barre latérale n'affiche que la section courante : on l'ouvre d'abord.
|
||||
await page.goto('/conges');
|
||||
await page.goto('/absences/calendrier');
|
||||
// « Politiques de congés » fait partie du périmètre visé mais n'est pas
|
||||
// encore construit : l'entrée reste, et mène à un écran qui le dit.
|
||||
await page.getByRole('link', { name: 'Politiques de congés' }).click();
|
||||
|
||||
@@ -21,7 +21,9 @@ describe('matches', () => {
|
||||
});
|
||||
|
||||
it('écarte les liens d’ancre', () => {
|
||||
expect(matches('/conges#attente', '/conges')).toBe(false);
|
||||
expect(
|
||||
matches('/absences/calendrier#compteurs', '/absences/calendrier'),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -61,7 +63,8 @@ describe('sectionForPath', () => {
|
||||
it('trouve la section portant la route courante', () => {
|
||||
expect(sectionForPath('/planning/semaine').id).toBe('plannings');
|
||||
expect(sectionForPath('/equipe/camille-ferrand').id).toBe('equipe');
|
||||
expect(sectionForPath('/conges').id).toBe('conges');
|
||||
expect(sectionForPath('/absences/calendrier').id).toBe('conges');
|
||||
expect(sectionForPath('/absences/a-traiter').id).toBe('conges');
|
||||
});
|
||||
|
||||
it('retombe sur la première section pour une route inconnue', () => {
|
||||
|
||||
Reference in new issue
Block a user