test: le faux t des tests de rendu rend la clé brute, un appel à t oublié passe inaperçu #389

Closed
opened 2026-10-05 23:24:06 +00:00 by maximus · 1 comment
Owner

Planification du 2026-10-10 (/plan-run, milestone planned-2026-10-10-fiabilite-tests) : les sections ci-dessous, à partir de « Depends on », priment sur le texte d'analyse en cas d'écart.

Analyse /analyze du 2026-10-10, lue sur main 87920ec. Corps d'origine archivé en commentaire : la liste des fichiers a dérivé (8 → 12).

Contexte

Constat de la revue de la PR #387 (#370), suggestion S1 : un faux t qui rend la clé telle quelle cache un appel à t oublié. Un composant qui affiche license.removeKey.confirmValid au lieu du texte traduit passe toute la suite (mesuré sur la tête de #387 : 1487 tests sur 1487 verts).

2cbc886 a marqué la sortie dans useLicenseMachines.test.ts (fonction echo, L664) et LicenseCard.render.test.tsx : t(clé[options]). Depuis, la forme marquée est devenue la convention de fait (12 fichiers), mais elle est recopiée dans chaque fichier, et la pile du 2026-10-08 a ajouté quatre fichiers à t brut.

État au 2026-10-10 (inventaire scripté)

t brut, 12 fichiers :

  • src/components/balance/PriceFetchControl.test.tsx
  • src/components/dashboard/OnboardingChecklist.test.tsx
  • src/components/import/ImportEmptyState.test.tsx
  • src/components/import/SourceList.test.tsx (ajouté le 2026-10-08)
  • src/components/import/WizardNavigation.test.tsx (ajouté le 2026-10-08)
  • src/components/reports/FilterPanel.test.tsx
  • src/components/settings/DocsSubsections.test.tsx (cas particulier : rend un FIXTURE pour certaines clés, à garder pour ces clés)
  • src/components/settings/LicenseKeyForm.render.test.tsx
  • src/components/settings/PriceFetchConsentToggle.test.tsx
  • src/components/shared/UpsellCtas.render.test.tsx
  • src/components/transactions/TransactionTable.render.test.tsx (ajouté le 2026-10-08)
  • src/pages/DashboardPage.render.test.tsx (ajouté le 2026-10-08)

Déjà marqués, 12 fichiers (copie locale de la même fonction) : BudgetTable.render, BudgetTable.wiring, DashboardEmptyState.render, AppShell.render, OnboardingBanner.render, StepCard.render, LicenseCard.render, BudgetPage.render, BudgetPage.wiring, ImportPage.render, UsersSettingsPage, TransactionsPage.render.

Décision (Max, 2026-10-10)

Module partagé + migration. Un seul faux t marqué dans src/test/i18nMock.ts, adopté par les 24 fichiers (bruts et déjà marqués), chaque fichier brut prouvé par une mutation.

Travail à faire

  • src/test/i18nMock.ts : markedT(key, options?) qui rend t(clé) ou t(clé[a=1,b=2]), et une fabrique i18nMock({ language?, fixture? }) pour vi.mock("react-i18next", ...) (hoisting : import dynamique dans la fabrique). fixture couvre le cas de DocsSubsections.
  • Remplacer echo de useLicenseMachines.test.ts par markedT.
  • Migrer les 12 fichiers bruts ; réécrire sous forme marquée les assertions qui nomment un texte affiché (les assertions par sous-chaîne sur une clé nue restent valides).
  • Migrer les 12 fichiers déjà marqués vers le module (suppression des copies, sans changer les assertions).
  • docs/architecture.md, section ## Tests (vitest sans jsdom) (créée par #409) : convention « jamais de t brut, utiliser i18nMock ».
  • Pas d'entrée CHANGELOG (tests seulement).

Fichiers concernés

  • src/test/i18nMock.ts (nouveau), src/hooks/useLicenseMachines.test.ts
  • les 24 fichiers listés plus haut
  • docs/architecture.md

Surface de test

  • Pour chaque composant des 12 fichiers bruts : une mutation « un t retiré du composant » qui fait rougir au moins un test (code de sortie 1). Si un composant n'a aucune assertion sur un texte affiché, en ajouter une.
  • Garde contre la régression : src/__integration__/i18n-mock-guard.test.ts (convention de transactions-transfer-icon.test.ts : readFileSync, import.meta.dirname), liste les fichiers par readdirSync(src, {{ recursive: true }}), et échoue sur tout useTranslation: ou t: ( dans un fichier *.test.ts(x) hors de src/test/i18nMock.ts (s'exclut lui-même).

Critères d'acceptation

  • Plus aucun mock de react-i18next ne rend une clé brute ; un seul faux t dans le dépôt.
  • Pour chaque composant des 12 fichiers bruts, une mutation « t retiré » rougit.
  • Le garde sur les sources rougit si on ajoute un mock local.
  • npm test vert.

Complexité estimée

Simple à medium (mécanique, 24 fichiers).

Liens

PR #387 (revue S1), 2cbc886 ; #409 (harnais React, module voisin src/test/hookHarness.ts) ; #369 (touche TransactionTable.render.test.tsx).


Depends on

Critères d'acceptation (planification)

  • Liste des 24 fichiers revérifiée exacte à la revue (12 bruts, 12 marqués). Recouvrement avec #409 : BudgetTable.wiring, BudgetPage.wiring, UsersSettingsPage seulement (#409 est mergée avant : partir de son état).
  • Une seule PR, commits dans cet ordre : module + echo ; les 12 fichiers bruts avec leurs mutations ; les 12 fichiers marqués ; la garde (verte seulement une fois les 24 migrés).
  • La PR porte un tableau fichier / mutation « t retiré » / test rouge.

Review caveats

  • 🟢 PR volumineuse mais faisable ; l'ordre des commits ci-dessus sert la relecture.
  • 🟢 Garde par mots-clés (useTranslation:, t: () plutôt que par analyse de la fabrique : moins fragile.

Décisions prises en planification

  • Module partagé + migration des 24 fichiers (Max, 2026-10-10, /analyze).
  • Garde dans src/__integration__/ (décision de planification).
  • Sections de docs/architecture.md fixées pour toute la milestone : ### Accès DB et transactions (sous la section Base de données) et ## Tests (vitest sans jsdom) (juste avant CI/CD). La première issue de la pile qui en a besoin crée la section ; les suivantes y ajoutent.

Spec source

spec-plan-fiabilite-tests.md (local, ignoré par git)

> **Planification du 2026-10-10** (`/plan-run`, milestone `planned-2026-10-10-fiabilite-tests`) : les sections ci-dessous, à partir de « Depends on », **priment** sur le texte d'analyse en cas d'écart. > Analyse `/analyze` du 2026-10-10, lue sur `main` `87920ec`. Corps d'origine archivé en commentaire : la liste des fichiers a dérivé (8 → 12). ## Contexte Constat de la revue de la PR #387 (#370), suggestion S1 : un faux `t` qui rend la clé telle quelle cache un appel à `t` oublié. Un composant qui affiche `license.removeKey.confirmValid` au lieu du texte traduit passe toute la suite (mesuré sur la tête de #387 : 1487 tests sur 1487 verts). `2cbc886` a marqué la sortie dans `useLicenseMachines.test.ts` (fonction `echo`, L664) et `LicenseCard.render.test.tsx` : `t(clé[options])`. Depuis, la forme marquée est devenue la convention de fait (12 fichiers), mais elle est recopiée dans chaque fichier, et la pile du 2026-10-08 a ajouté quatre fichiers à `t` brut. ### État au 2026-10-10 (inventaire scripté) **`t` brut, 12 fichiers** : - `src/components/balance/PriceFetchControl.test.tsx` - `src/components/dashboard/OnboardingChecklist.test.tsx` - `src/components/import/ImportEmptyState.test.tsx` - `src/components/import/SourceList.test.tsx` (ajouté le 2026-10-08) - `src/components/import/WizardNavigation.test.tsx` (ajouté le 2026-10-08) - `src/components/reports/FilterPanel.test.tsx` - `src/components/settings/DocsSubsections.test.tsx` (cas particulier : rend un `FIXTURE` pour certaines clés, à garder pour ces clés) - `src/components/settings/LicenseKeyForm.render.test.tsx` - `src/components/settings/PriceFetchConsentToggle.test.tsx` - `src/components/shared/UpsellCtas.render.test.tsx` - `src/components/transactions/TransactionTable.render.test.tsx` (ajouté le 2026-10-08) - `src/pages/DashboardPage.render.test.tsx` (ajouté le 2026-10-08) **Déjà marqués, 12 fichiers** (copie locale de la même fonction) : `BudgetTable.render`, `BudgetTable.wiring`, `DashboardEmptyState.render`, `AppShell.render`, `OnboardingBanner.render`, `StepCard.render`, `LicenseCard.render`, `BudgetPage.render`, `BudgetPage.wiring`, `ImportPage.render`, `UsersSettingsPage`, `TransactionsPage.render`. ## Décision (Max, 2026-10-10) **Module partagé + migration.** Un seul faux `t` marqué dans `src/test/i18nMock.ts`, adopté par les 24 fichiers (bruts et déjà marqués), chaque fichier brut prouvé par une mutation. ## Travail à faire - [ ] `src/test/i18nMock.ts` : `markedT(key, options?)` qui rend `t(clé)` ou `t(clé[a=1,b=2])`, et une fabrique `i18nMock({ language?, fixture? })` pour `vi.mock("react-i18next", ...)` (hoisting : import dynamique dans la fabrique). `fixture` couvre le cas de `DocsSubsections`. - [ ] Remplacer `echo` de `useLicenseMachines.test.ts` par `markedT`. - [ ] Migrer les 12 fichiers bruts ; réécrire sous forme marquée les assertions qui nomment un texte affiché (les assertions par sous-chaîne sur une clé nue restent valides). - [ ] Migrer les 12 fichiers déjà marqués vers le module (suppression des copies, sans changer les assertions). - [ ] `docs/architecture.md`, section `## Tests (vitest sans jsdom)` (créée par #409) : convention « jamais de `t` brut, utiliser `i18nMock` ». - Pas d'entrée CHANGELOG (tests seulement). ## Fichiers concernés - `src/test/i18nMock.ts` (nouveau), `src/hooks/useLicenseMachines.test.ts` - les 24 fichiers listés plus haut - `docs/architecture.md` ## Surface de test - Pour chaque composant des 12 fichiers bruts : une mutation « un `t` retiré du composant » qui fait rougir au moins un test (code de sortie 1). Si un composant n'a aucune assertion sur un texte affiché, en ajouter une. - Garde contre la régression : `src/__integration__/i18n-mock-guard.test.ts` (convention de `transactions-transfer-icon.test.ts` : `readFileSync`, `import.meta.dirname`), liste les fichiers par `readdirSync(src, {{ recursive: true }})`, et échoue sur tout `useTranslation:` ou `t: (` dans un fichier `*.test.ts(x)` hors de `src/test/i18nMock.ts` (s'exclut lui-même). ## Critères d'acceptation - [ ] Plus aucun mock de `react-i18next` ne rend une clé brute ; un seul faux `t` dans le dépôt. - [ ] Pour chaque composant des 12 fichiers bruts, une mutation « `t` retiré » rougit. - [ ] Le garde sur les sources rougit si on ajoute un mock local. - [ ] `npm test` vert. ## Complexité estimée Simple à medium (mécanique, 24 fichiers). ## Liens PR #387 (revue S1), `2cbc886` ; #409 (harnais React, module voisin `src/test/hookHarness.ts`) ; #369 (touche `TransactionTable.render.test.tsx`). --- ## Depends on - #409 ## Critères d'acceptation (planification) - [ ] Liste des 24 fichiers revérifiée exacte à la revue (12 bruts, 12 marqués). Recouvrement avec #409 : `BudgetTable.wiring`, `BudgetPage.wiring`, `UsersSettingsPage` seulement (#409 est mergée avant : partir de son état). - [ ] Une seule PR, commits dans cet ordre : module + `echo` ; les 12 fichiers bruts avec leurs mutations ; les 12 fichiers marqués ; la garde (verte seulement une fois les 24 migrés). - [ ] La PR porte un tableau fichier / mutation « `t` retiré » / test rouge. ## Review caveats - 🟢 PR volumineuse mais faisable ; l'ordre des commits ci-dessus sert la relecture. - 🟢 Garde par mots-clés (`useTranslation:`, `t: (`) plutôt que par analyse de la fabrique : moins fragile. ## Décisions prises en planification - Module partagé + migration des 24 fichiers (Max, 2026-10-10, `/analyze`). - Garde dans `src/__integration__/` (décision de planification). - Sections de `docs/architecture.md` fixées pour toute la milestone : `### Accès DB et transactions` (sous la section Base de données) et `## Tests (vitest sans jsdom)` (juste avant CI/CD). La première issue de la pile qui en a besoin crée la section ; les suivantes y ajoutent. ## Spec source `spec-plan-fiabilite-tests.md` (local, ignoré par git)
maximus added the
status:triage
type:refactor
source:analyste
labels 2026-10-05 23:24:06 +00:00
Author
Owner

Archive avant réécriture par /analyze (2026-10-10, lu sur main 87920ec). Le corps est réécrit avec les décisions de Max du jour ; le texte d'origine est conservé ci-dessous.

Corps d'origine

Contexte

Constat de la revue de la PR #387 (#370), suggestion S1 : le faux t des tests rend la clé telle quelle quand l'appel n'a pas d'options. Un appel à t oublié ne se voit donc pas : un composant qui affiche license.removeKey.confirmValid au lieu du texte traduit passe toute la suite. Mesuré sur la tête de #387 : la première confirmation du retrait passée sans t, et la raison d'échec affichée sur la carte passée sans t, laissaient 1487 tests sur 1487 verts.

Ce qui est déjà corrigé

Avant le merge de la pile #386 → #387 → #388, le commit 2cbc886 a marqué la sortie du faux t dans les deux fichiers de la pile : t(clé[options]) au lieu de clé[options].

  • src/hooks/useLicenseMachines.test.ts (fonction echo) ;
  • src/components/settings/LicenseCard.render.test.tsx (mock de react-i18next).

Les assertions écrites sous la forme marquée y rougissent désormais sur une chaîne qui a sauté t : 18, 4 et 1 tests rouges selon la mutation. Les assertions par sous-chaîne sur une clé nue restent valides, puisque la clé figure dans la marque.

Ce qui reste

Huit fichiers mockent encore react-i18next avec un t qui rend la clé brute :

  • src/components/shared/UpsellCtas.render.test.tsx
  • src/components/settings/LicenseKeyForm.render.test.tsx
  • src/components/settings/PriceFetchConsentToggle.test.tsx
  • src/components/settings/DocsSubsections.test.tsx
  • src/components/balance/PriceFetchControl.test.tsx
  • src/components/import/ImportEmptyState.test.tsx
  • src/components/dashboard/OnboardingChecklist.test.tsx
  • src/components/reports/FilterPanel.test.tsx

Piste

  • Un helper partagé (par exemple markedT dans un module de test) qui rend t(clé[options]), adopté fichier par fichier.
  • Dans chaque fichier, réécrire sous la forme marquée les assertions qui nomment un texte affiché. Les assertions par sous-chaîne restent valides telles quelles.
  • Prouver chaque fichier par une mutation qui retire un t du composant testé.

Critères d'acceptation

  • Plus aucun mock de react-i18next dans les tests ne rend une clé brute.
  • Pour chaque composant concerné, au moins une mutation « t retiré » fait rougir un test.
  • npm test vert.
Archive avant réécriture par `/analyze` (2026-10-10, lu sur `main` `87920ec`). Le corps est réécrit avec les décisions de Max du jour ; le texte d'origine est conservé ci-dessous. <details><summary>Corps d'origine</summary> ## Contexte Constat de la revue de la PR #387 (#370), suggestion S1 : le faux `t` des tests rend la clé telle quelle quand l'appel n'a pas d'options. Un appel à `t` oublié ne se voit donc pas : un composant qui affiche `license.removeKey.confirmValid` au lieu du texte traduit passe toute la suite. Mesuré sur la tête de #387 : la première confirmation du retrait passée sans `t`, et la raison d'échec affichée sur la carte passée sans `t`, laissaient 1487 tests sur 1487 verts. ## Ce qui est déjà corrigé Avant le merge de la pile #386 → #387 → #388, le commit `2cbc886` a marqué la sortie du faux `t` dans les deux fichiers de la pile : `t(clé[options])` au lieu de `clé[options]`. - `src/hooks/useLicenseMachines.test.ts` (fonction `echo`) ; - `src/components/settings/LicenseCard.render.test.tsx` (mock de `react-i18next`). Les assertions écrites sous la forme marquée y rougissent désormais sur une chaîne qui a sauté `t` : 18, 4 et 1 tests rouges selon la mutation. Les assertions par sous-chaîne sur une clé nue restent valides, puisque la clé figure dans la marque. ## Ce qui reste Huit fichiers mockent encore `react-i18next` avec un `t` qui rend la clé brute : - `src/components/shared/UpsellCtas.render.test.tsx` - `src/components/settings/LicenseKeyForm.render.test.tsx` - `src/components/settings/PriceFetchConsentToggle.test.tsx` - `src/components/settings/DocsSubsections.test.tsx` - `src/components/balance/PriceFetchControl.test.tsx` - `src/components/import/ImportEmptyState.test.tsx` - `src/components/dashboard/OnboardingChecklist.test.tsx` - `src/components/reports/FilterPanel.test.tsx` ## Piste - Un helper partagé (par exemple `markedT` dans un module de test) qui rend `t(clé[options])`, adopté fichier par fichier. - Dans chaque fichier, réécrire sous la forme marquée les assertions qui nomment un texte affiché. Les assertions par sous-chaîne restent valides telles quelles. - Prouver chaque fichier par une mutation qui retire un `t` du composant testé. ## Critères d'acceptation - [ ] Plus aucun mock de `react-i18next` dans les tests ne rend une clé brute. - [ ] Pour chaque composant concerné, au moins une mutation « `t` retiré » fait rougir un test. - [ ] `npm test` vert. </details>
maximus added
status:ready
and removed
status:triage
labels 2026-10-10 23:11:58 +00:00
maximus added this to the planned-2026-10-10-fiabilite-tests milestone 2026-10-10 23:37:36 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-10-12 23:48:25 +00:00
maximus added
status:review
and removed
status:in-progress
labels 2026-10-12 23:59:32 +00:00
maximus added
status:approved
and removed
status:review
labels 2026-10-13 00:53:45 +00:00
maximus removed the
status:approved
label 2026-10-14 00:29:22 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#389
No description provided.