docs(knowledge): capitalisation frontend — intégration du triage local (mai-juin 2026)

Triage et intégration des propositions frontend du buffer 95_a_capitaliser.md
(lot local RL799_V2/Vue3 + app-alexandrie/RN-Expo, mai-juin 2026).

~73 entrées intégrées sur knowledge/frontend/ + 1 nouveau fichier, dont :
- patterns/state.md : race-token partagé latest-wins (fusion 3 props), capture sync anti-race,
  event bus timestamp, clé cache composite, état dérivé = computed
- risques/state.md : 9 risques Zustand/store (fetchId reset, useRef remount, re-fetch infini
  sur [], flag optimiste écrasé, cache détail/liste stale, latch sans reset, :key index)
- patterns/navigation.md : Expo Router (tab bar, useFocusEffect, Href typé, routing pur fusionné)
- patterns/general.md : helpers temps purs, composants génériques + skeleton, fail-fast, touch target
- risques/general.md : 24 risques (sweep statique, filtre client liste paginée, hooks avant return,
  a11y VoiceOver/disabled, redirection allowlist, RangeError toISOString, section i18n...)
- design-tokens (cluster theming light/dark MD3), tests, performance, react-native, nextjs
- NOUVEAU risques/responsive.md (gating par capacité d'input + checklist régressions mobile)
- READMEs patterns/risques mis à jour

Doublons inter-fichiers évités (vérifié : aucune ancre dupliquée introduite).
Rejets (doublons 91/9/87), reciblages workflow (156/257) et bloc 32 (CLAUDE projet) non intégrés ici.
Source 95_a_capitaliser.md non purgée (purge en fin de capitalisation complète).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MaksTinyWorkshop
2026-06-25 15:31:53 +02:00
parent f1b783407a
commit 5f5c87296e
15 changed files with 2439 additions and 12 deletions
+107
View File
@@ -313,3 +313,110 @@ Si tes tests doivent être systématiquement mis à jour à chaque refactor, c'e
- Pour les composants interactifs, compléter par au moins un test de mount via `@vue/test-utils` qui vérifie le render sans crash
- Contexte technique : Vue 3 / Vitest — RL799_V2 29-04-2026
---
<a id="risque-dupliquer-styles-pour-tester-hook"></a>
## Dupliquer les styles pour tester un composant qui utilise un hook
### Risques
- Pour rendre testable un composant qui style via un hook (`useThemedColors`), on duplique les styles en `export const xxxStyles = StyleSheet.create({...})` à côté du `makeStyles(themed)` interne
- Toute modif de `makeStyles` ne propage pas à la copie statique → les tests passent sur du code mort ; la régression n'est vue qu'au smoke device
### Symptômes
- Deux `StyleSheet.create` dans le même fichier (interne + exporté pour les tests) avec les mêmes définitions
### Bonnes pratiques / mitigations
```typescript
// ✅ passer la palette statique à makeStyles : 1 ligne, 0 duplication, source unique
export const sectionHeaderStyles = makeStyles(colors);
```
- Si le composant n'expose pas `makeStyles`, exposer la fonction (pas le résultat) et tester `makeStyles(mock)`
- Garde-fou review : deux `StyleSheet.create` dans le même fichier = suspicion de duplication
- Contexte technique : React Native — app-alexandrie (ux-cleanup-5, `SectionHeader.tsx`), 29-05-2026
---
<a id="risque-fix-visuel-plumbing-sans-test"></a>
## Fix visuel de plumbing sans test = régression silencieuse garantie
### Risques
- Un bug "visuel" venant d'un câblage cassé (theme provider, navigation theme, font/locale loader) fixé directement dans le `useMemo` racine → non testable
- Une PR future qui re-câble le mauvais provider ne casse rien en CI mais ré-introduit le bug en prod
### Symptômes
- Fix livré sans test de non-régression alors que la cause root est testable en isolation
### Bonnes pratiques / mitigations
- Extraire la dérivation en module pur (`buildXxxFrom(scheme, tokens) → Theme`)
- Ajouter ≥ 2 tests : un par scheme + un garde-fou prouvant que les valeurs natives OS ne fuient pas (`expect(theme.colors.background).not.toBe('#ffffff')`)
- Contexte technique : React Native — app-alexandrie (ux-cleanup-8 H2, `navigation-theme.ts`), 29-05-2026
---
<a id="risque-test-fanout-sans-compte"></a>
## Test de ciblage/fan-out qui assert le prédicat mais pas le COMPTE
### Risques
- `assert(recipients.every(r => r.grade === 'Compagnon'))` passe AUSSI si on ne notifie qu'1 destinataire sur 9 (ou zéro) — `.every()` sur une liste partielle/vide est vrai par vacuité
- Un bug de complétude (ciblage partiel, exclusion silencieuse d'actifs) reste invisible
### Symptômes
- Test "X notifie/cible Y" vert alors que le ciblage est incomplet
### Bonnes pratiques / mitigations
- Ajouter `assert.equal(recipients.length, EXPECTED)` où EXPECTED est calculé **dynamiquement** depuis les fixtures (`seedUsers.filter(...)`), jamais hardcodé
- Le `.every()` valide la pureté du ciblage, le `.length` valide la complétude — les deux sont nécessaires
- Contexte technique : tests de notification — RL799 (review v2-1-3), 13-06-2026
---
<a id="risque-stub-enfant-props-calculees"></a>
## Stub de composant enfant en mount test : déclarer aussi les props CALCULÉES
### Risques
- Un stub d'enfant qui ne déclare que les props affichées laisse non testée la logique de calcul des props non lues (`:variant="sourceVariant(x)"`)
- `vue-tsc` valide que la valeur est une variante acceptée, mais PAS que la bonne branche est prise au runtime → une inversion de logique passe typecheck + mount
### Symptômes
- Une fonction de calcul de prop n'est jamais exercée au runtime ; seul le typecheck la couvre
### Bonnes pratiques / mitigations
- Le stub expose la prop calculée (`props: ['label','variant']`) et la reflète dans un attribut testable (`:data-variant="variant"`) ; le test asserte la valeur
- Règle : tout `:prop="fn(...)"` dans un template mérite une assertion runtime sur la valeur résultante (surtout si elle prépare une extension future)
- Contexte technique : Vue 3 / @vue/test-utils — RL799, 22-06-2026
---
<a id="risque-module-garde-par-office-trous-test"></a>
## Module gardé par office (rôle dérivé) — 2 trous de test systématiques
### Risques
- Pattern « guard backend `requireOffice(office)` + nav item conditionné + icône `OfficerRoleIcon` » : deux assertions manquent quasi toujours sans que la suite verte ne le rattrape
- (1) aucun test ne valide le rendu de l'icône d'office en navbar mobile (si `isOfficerRole(office)` renvoie `false` ou si le wrapper de taille manque, l'icône ne rend rien / déborde, sans erreur)
- (2) le test d'accès API mocke les offices via le token (`createTestToken({ offices: ['x'] })`), pas via un vrai mandat en DB → la chaîne LIVE `mandat actif → offices résolus → accès` n'est jamais couverte bout-en-bout
### Symptômes
- Tous les tests passent alors que l'icône d'office ne rend rien et que la chaîne mandat→accès n'est pas testée
### Bonnes pratiques / mitigations
1. Test mount transverse : pour CHAQUE office routé, vérifier que le nav item rend une icône d'office non vide et bornée en taille
2. Au moins un test par domaine créant un mandat actif en DB → accès 200, et un mandat révoqué → 403
- À traiter dans un chantier « tests offices » dédié (raffinement transverse, pas story par story) mais à décider sciemment dès le câblage du 1er office
- Contexte technique : Vue 3 / backend — RL799 (review v2-5-2), 22-06-2026