Files
planflow/tests/e2e/registre.spec.ts
T
MichaelandClaude Opus 5 894e880198 Alléger l'annuaire
Le formulaire d'embauche, posé au bas de la liste, occupait plus de place
que l'effectif qu'on vient consulter — une quinzaine de champs déployés en
permanence pour un geste occasionnel. Il s'ouvre désormais en modale,
depuis le bouton d'en-tête.

`<dialog>` natif plutôt qu'un panneau maison : le piège de focus, la
fermeture par Échap et le fond inerte viennent avec, et une `<div>` doit
les réimplémenter sans jamais les tenir tout à fait.

Le tableau perd sa carte et ses fonds : une liste de personnes se lit
mieux sans cadre autour. Les colonnes suivent l'annuaire de référence —
collaborateur, rôle, email, mobile, rattachement, invitation. Le contrat
quitte le tableau, où il doublait le filtre qui le cherche déjà ; son
absence reste signalée là où elle compte, dans le rattachement.

Le décompte ne s'affiche plus que filtré : « 87 salariés » au-dessus de 87
lignes n'apprend rien.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 15:45:28 +02:00

87 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from '@playwright/test';
/**
* Registre de paramétrage et création d'un salarié sans accès applicatif.
*
* Ces parcours n'éprouvent pas l'authentification : ils réutilisent la session
* commune plutôt que d'ouvrir la leur. La direction porte un second facteur, et
* un code TOTP ne sert qu'une fois — deux connexions parallèles sur ce compte
* échoueraient, à raison.
*/
test('la direction lit et alimente le registre de paramétrage', async ({
page,
}) => {
await page.goto('/reglages/registre');
await expect(
page.getByRole('heading', { name: 'Registre de paramétrage juridique' }),
).toBeVisible();
const parameter = `Durée quotidienne maximale ${Date.now()}`;
// Ciblage par attribut `name` : les libellés portent un texte d'aide, et
// celui de « Source » contient lui-même le mot « valeur », ce qui rend la
// correspondance par libellé ambiguë.
const form = page.locator('form').filter({ hasText: 'Consigner' });
await form.locator('input[name="key"]').fill(parameter);
await form.locator('input[name="value"]').fill('10 h');
await form
.locator('input[name="source"]')
.fill('IDCC 1517 — texte consolidé Legifrance');
await form.locator('input[name="population"]').fill('Tous les salariés');
await page.getByRole('button', { name: 'Consigner' }).click();
const row = page.getByRole('row', { name: new RegExp(parameter) });
await expect(row).toBeVisible();
// Consigné n'est pas approuvé : la matrice exige un approbateur nommé.
await row.getByRole('button', { name: 'Approuver' }).click();
await expect(row.getByText(/Approuvé le/)).toBeVisible();
});
test('un salarié sans compte applicatif est créable', async ({ page }) => {
await page.goto('/equipe');
await expect(page.getByRole('heading', { name: 'Équipe' })).toBeVisible();
// L'effectif vient de la base, pas du module de démonstration : un annuaire
// fabriqué à l'écran ne se filtrerait pas par matricule.
await page
.getByPlaceholder('Rechercher par prénom, nom ou matricule.')
.fill('E0001');
await expect(page.getByText(/^1 sur \d+ salariés$/)).toBeVisible();
await page.goto('/equipe');
// Nom unique par exécution : la base de test n'est pas remise à zéro entre
// deux passages, et un nom fixe finirait par désigner plusieurs salariés.
const matricule = `E9${Date.now() % 100000}`;
const nom = `Sanscompte${matricule}`;
// Le formulaire d’embauche n’est plus posé au bas de la liste : il s’ouvre
// en modale, à la demande.
await page.getByRole('button', { name: 'Ajouter un collaborateur' }).click();
const form = page.locator('form').filter({ hasText: 'Ajouter' });
await form.locator('input[name="firstName"]').fill('Sans');
await form.locator('input[name="lastName"]').fill(nom);
await form.locator('input[name="employeeNumber"]').fill(matricule);
// Le formulaire propose d’ouvrir un contrat d’emblée : ce parcours n’en veut
// pas, et un salarié sans contrat doit rester créable.
await form.getByLabel('Ouvrir un contrat maintenant').uncheck();
await page.getByRole('button', { name: 'Ajouter' }).click();
await expect(page.getByText('Salarié ajouté.')).toBeVisible();
// Rechargement explicite : ce qui est vérifié ici est la persistance et la
// présence dans l'annuaire, pas le moment exact où la revalidation atteint
// le rendu courant.
await page.reload();
// Un salarié sans adresse doit exister : la plupart des équipes de vente ne
// se connectent jamais à l'outil.
// Sans compte applicatif, l'annuaire affiche le matricule sous le nom : c'est
// la seule adresse à laquelle on désigne ce salarié.
await expect(page.getByText(`Matricule ${matricule}`)).toBeVisible();
// Le nom vit sur le dossier, pas sur le compte : un salarié sans accès
// applicatif doit tout de même figurer nommément au registre du personnel.
await expect(
page.getByRole('link', { name: new RegExp(`Sans ${nom}`) }),
).toBeVisible();
});