From ad12bd45b2190bf2e5265782588d45a5bb719678 Mon Sep 17 00:00:00 2001 From: Guy Corbaz Date: Sat, 3 Oct 2026 12:44:10 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix(e2e):=20la=20fiche=20produit=20attend?= =?UTF-8?q?=20sa=20cr=C3=A9ation=20avant=20de=20relire=20la=20liste=20;=20?= =?UTF-8?q?traces=20conserv=C3=A9es=20sur=20=C3=A9chec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit product-revenue-account.spec.ts:133 relisait la liste par l'API sans attendre le POST qu'il venait de déclencher : sous la charge de la suite complète, la liste revenait vide. Prouvé par un délai injecté (l'ancien test échoue avec le symptôme exact, le corrigé passe). Classé à tort en pollution d'état. products.spec.ts:166 n'a pas de cause établie (non reproduit) : la trace est désormais conservée sur échec, et docs/testing.md dit de mettre test-results/ à l'abri avant tout rejeu. Co-Authored-By: Claude Opus 5.5 --- docs/testing.md | 17 +++++++++++++++++ frontend/playwright.config.ts | 5 +++++ .../tests/e2e/product-revenue-account.spec.ts | 17 ++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/testing.md b/docs/testing.md index f2032cd8d..d3e2727b6 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -406,6 +406,23 @@ 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), 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. + ### Comment lire un rouge, dans l'ordre 1. **Comparer les fichiers en échec à la liste ci-dessus.** Un échec hors liste est une diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index fb4e82f02..1297c161a 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -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` (2026-10-03) n'a pas + // pu être établie. Coût : de l'espace disque, sur les seuls échecs. + trace: 'retain-on-failure', }, }; diff --git a/frontend/tests/e2e/product-revenue-account.spec.ts b/frontend/tests/e2e/product-revenue-account.spec.ts index f79ba97aa..bba32003e 100644 --- a/frontend/tests/e2e/product-revenue-account.spec.ts +++ b/frontend/tests/e2e/product-revenue-account.spec.ts @@ -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, @@ -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(); } // =========================================================================== From f57174e92687caee36e045acea52684f52947f08 Mon Sep 17 00:00:00 2001 From: Guy Corbaz Date: Sat, 3 Oct 2026 14:43:42 +0200 Subject: [PATCH 2/2] =?UTF-8?q?docs(e2e):=20KF-054=20(#498)=20nomm=C3=A9e?= =?UTF-8?q?=20l=C3=A0=20o=C3=B9=20products.spec.ts:166=20est=20d=C3=A9crit?= =?UTF-8?q?e=20(refs=20#498)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/testing.md | 6 ++++-- frontend/playwright.config.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/testing.md b/docs/testing.md index d3e2727b6..980e5b864 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -414,8 +414,8 @@ injectant un délai de 1,5 s sur le POST : l'ancien test échoue avec ce message 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), lui, **n'a pas de cause -établie** : ni reproduit en enchaînant les specs voisines, ni sous délai injecté des lectures ou de +`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 @@ -423,6 +423,8 @@ frontend/test-results /quelque/part/`) : Playwright vide ce répertoire au lance 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 diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 1297c161a..8253fb7ee 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -59,7 +59,7 @@ const config: PlaywrightTestConfig = { 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` (2026-10-03) n'a pas + // 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', },