Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,25 @@ comme s'il s'agissait du huitième, toujours le même.** C'était trop précis,
un lecteur voyant rougir une autre spec en aurait conclu à une régression. Corrigé au run du
2026-08-27, qui a rendu un huitième différent.

⚠️ **Le 2026-10-03, l'un de ces « huitièmes » s'est révélé ne PAS être de la pollution.**
`product-revenue-account.spec.ts:133` relisait la liste des produits par l'API **sans attendre**
le POST de création qu'il venait de déclencher : sous la charge de la suite complète, la relecture
partait la première et rendait une liste vide (`Expected: 6, Received: undefined`). Prouvé en
injectant un délai de 1,5 s sur le POST : l'ancien test échoue avec ce message exact, le test
corrigé passe. Corrigé (`fillProductForm` attend la réponse du serveur). *Un test qui passe rejoué
seul n'est pas forcément pollué : il peut aussi être une course que la charge révèle.*

`products.spec.ts:166` (« doublon », bouton *Créer* resté désactivé 30 s — **KF-054, [#498]**), lui,
**n'a pas de cause établie** : ni reproduit en enchaînant les specs voisines, ni sous délai injecté des lectures ou de
la création. D'où, depuis cette date, **`trace: 'retain-on-failure'`** dans `playwright.config.ts`.

⛔ **Avant de rejouer seul un échec, mettre `frontend/test-results/` à l'abri** (`cp -r
frontend/test-results /quelque/part/`) : Playwright vide ce répertoire au lancement, et le rejeu
efface la trace et l'instantané du run qui a échoué — c'est exactement ce qui a privé
`products.spec.ts:166` de diagnostic.

[#498]: https://github.com/guycorbaz/kesh/issues/498

### Comment lire un rouge, dans l'ordre

1. **Comparer les fichiers en échec à la liste ci-dessus.** Un échec hors liste est une
Expand Down
5 changes: 5 additions & 0 deletions frontend/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ const config: PlaywrightTestConfig = {
baseURL: process.env.KESH_BACKEND_URL ?? 'http://127.0.0.1',
locale: 'fr-CH',
timezoneId: 'Europe/Zurich',
// Un échec intermittent ne se diagnostique que sur sa trace : rejoué seul,
// il passe, et le rejeu ÉCRASE `test-results/` — instantané compris. Sans
// trace conservée, la cause de `products.spec.ts:166` (KF-054, #498) n'a pas
// pu être établie. Coût : de l'espace disque, sur les seuls échecs.
trace: 'retain-on-failure',
},
};

Expand Down
17 changes: 16 additions & 1 deletion frontend/tests/e2e/product-revenue-account.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,16 @@ async function pickAccount(
await expect(field).toHaveValue(`${account.number} — ${account.name}`);
}

/** Remplit le dialogue de la fiche produit et enregistre. */
/**
* Remplit le dialogue de la fiche produit et enregistre — **et attend la réponse
* du serveur**.
*
* ⚠️ Sans cette attente, l'appelant qui relit la liste par l'API juste après
* court contre le POST : sous la charge de la suite complète, la relecture partait
* avant la création et rendait une liste vide (`defaultRevenueAccountId`
* `undefined`). Échec intermittent, vert rejoué seul — classé à tort en
* « pollution d'état » jusqu'au 2026-10-03.
*/
async function fillProductForm(
page: import('@playwright/test').Page,
name: string,
Expand All @@ -123,7 +132,13 @@ async function fillProductForm(
}
// ⚠️ Le libellé dépend du mode : « Créer » à la création, « Enregistrer » à
// l'édition (`+page.svelte:714-717`). La regex couvre les deux.
const saved = page.waitForResponse(
(r) =>
r.url().includes('/api/v1/products') &&
['POST', 'PUT'].includes(r.request().method())
);
await page.getByRole('button', { name: /^(Créer|Enregistrer)$/ }).click();
expect((await saved).ok(), 'la fiche produit doit être enregistrée').toBeTruthy();
}

// ===========================================================================
Expand Down
Loading