feat(r3.4): corrections de recette (8 écarts) + recherche globale ⌘K

Arbitrage du référent sur la revue pixel : tout corriger, activer la
recherche.

- Stock : filtre fournisseur, sous-seuil en tête, « Entrée de stock »
  depuis la liste ; fiche pièce : fournisseur → lien Tiers.
- Statistiques : période 3/6/12 mois (paramètre months au contrat).
- Tiers : rattachements syndic→site (migration r3_recette_fixes,
  Location.partnerId gardé CLIENT), éditable sur la fiche site, seedé.
- Bibliothèque : filtre « Rattaché à » + glisser-déposer (modale
  préremplie, rattachement toujours requis).
- Recherche globale : GET /search (73 opérations) — familles OT/
  ascenseurs/sites filtrées par la matrice, « voir autre » respecté ;
  topbar ⌘K, debounce, résultats groupés, navigation clavier.

74 tests API (8 nouveaux sur le scoping de la recherche), 14/14
Playwright dont un parcours « recette corrigée », 18/18 contrôles en
navigateur réel, zéro erreur console.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pr-daaif
2026-07-17 02:14:43 +01:00
parent c46a97ed08
commit 460ef4a80e
38 changed files with 1318 additions and 65 deletions

View File

@@ -48,7 +48,7 @@ test('recette R3 : tiers → pièce sous seuil → BC prérempli → réception
await page.getByLabel('Désignation *').fill(piece);
await page.getByLabel("Seuil d'alerte").fill('5');
await page.getByLabel('Prix initial (MAD)').fill('100');
await page.getByLabel('Fournisseur').selectOption({ label: fournisseur });
await page.getByLabel('Fournisseur', { exact: true }).selectOption({ label: fournisseur });
await page.getByRole('button', { name: 'Créer la pièce' }).click();
await expect(page.getByRole('heading', { name: piece })).toBeVisible();
@@ -157,3 +157,53 @@ test('recette R3 : coûts réels sur OT (prix + taux figés) + document + statis
await expect(page.getByText('Pannes par organe · 12 mois')).toBeVisible();
await expect(page.getByText('Top équipements en coût · 12 mois')).toBeVisible();
});
test('recette R3 corrigée : recherche ⌘K, tri/filtre stock, période stats, rattachements, dépôt', async ({
page,
}) => {
await connexionDemo(page, /Yasmine Alaoui/);
// Recherche globale : ⌘K → site (insensible à la casse), clic → fiche site
await page.keyboard.press('ControlOrMeta+k');
await page.keyboard.type('atlas');
await page.locator('.resultat', { hasText: 'Tour Atlas' }).first().click();
await expect(page).toHaveURL(/\/sites\//);
// le site porte son syndic (rattachement seedé, éditable par l'admin)
await expect(page.getByLabel('Client / syndic du site')).toHaveValue(/.+/);
// Recherche OT au clavier seul (Entrée sur le premier résultat)
await page.keyboard.press('ControlOrMeta+k');
await page.keyboard.type('bruit');
await page.locator('.resultat', { hasText: 'Bruit anormal' }).first().waitFor();
await page.keyboard.press('Enter');
await expect(page).toHaveURL(/\/ot\//);
// Stock : les pièces sous le seuil remontent en tête, filtre fournisseur,
// « Entrée de stock » accessible depuis la liste (choix de la pièce)
await page.getByRole('link', { name: 'Stock & achats' }).click();
await expect(page.locator('tbody tr').first().locator('.stock-bas')).toHaveText(/Sous le seuil/);
await page.getByLabel('Filtrer par fournisseur').selectOption({ label: 'Lubmaroc' });
await expect(page.locator('tbody tr', { hasText: 'P-0042' })).toHaveCount(1);
await page.getByLabel('Filtrer par fournisseur').selectOption({ index: 0 });
await page.getByRole('button', { name: 'Entrée de stock' }).click();
await expect(page.getByLabel('Pièce *')).toBeVisible();
await page.getByRole('button', { name: 'Annuler' }).click();
// Fiche pièce : le fournisseur est un lien vers les tiers
await page.getByRole('cell', { name: 'P-0113' }).click();
await page.getByRole('link', { name: 'Ascentech Maroc' }).click();
await expect(page).toHaveURL(/\/tiers/);
// Tiers : les syndics affichent leurs sites
await expect(page.getByRole('cell', { name: 'Tour Atlas' })).toBeVisible();
await expect(page.getByRole('cell', { name: 'Résidence Al Manar' })).toBeVisible();
// Statistiques : la période est un vrai sélecteur
await page.getByRole('link', { name: 'Statistiques', exact: true }).click();
await page.getByLabel('Période').selectOption('3');
await expect(page.getByText('OT clôturés · 3 mois')).toBeVisible();
// Bibliothèque : filtre « Rattaché à » + zone de glisser-déposer
await page.getByRole('link', { name: 'Fichiers' }).click();
await expect(page.getByLabel('Filtrer par appareil')).toBeVisible();
await expect(page.locator('.zone-depot')).toBeVisible();
});