Comment distinguer un vrai bug d'un test instable ?
Exécutez le test plusieurs fois sans les nouvelles tentatives et comptez. Un vrai bogue échoue de la même manière à chaque exécution, et un test instable réussit certaines exécutions et en échoue d'autres sans qu'aucun changement n'ait été apporté. L'exemple ci-dessous fait exactement cela sur n'importe quelle machine avec Playwright, puis montre ce que Nexus Studio fait de chaque résultat.
Par l'équipe Nexus Studio, Verdict System LLC. 27 octobre 2026.
Comment puis-je les différencier en une minute ?
Exécutez le test plusieurs fois de suite sans les nouvelles tentatives. Playwright le fait avec deux indicateurs : --retries=0, pour qu'une nouvelle tentative ne puisse pas masquer un échec, et --repeat-each=6, qui exécute chaque test six fois. Ensuite, comptez les résultats de chaque test.
- Il a échoué à chaque fois : considérez-le comme un bogue jusqu'à preuve du contraire. Un échec à chaque exécution peut tout de même provenir de l'environnement, tel qu'une requête bloquée ou un hôte inaccessible, alors lisez d'abord l'erreur.
- Il a réussi certaines exécutions et en a échoué d'autres : il est instable. Le code et le test n'ont pas changé entre ces exécutions, donc un élément instable est en cause, dans l'application ou dans le test.
- Il a réussi à chaque fois : rien à signaler pour le moment. Un défaut qui n'apparaît qu'une fois sur cinquante exécutions nécessite davantage d'exécutions, ou un coup d'œil à l'historique du test.
Puis-je l'essayer sur un exemple exécutable ?
Enregistrez ceci sous le nom bug-or-flaky.spec.js. Le premier test simule un comportement instable : il échoue une fois sur trois. Le second test est un vrai bogue : la page indique "Welcome" et le test attend "Welcome back", donc aucune exécution ne peut réussir.
import { test, expect } from '@playwright/test';
// Fails on its first attempt of every third run, passes otherwise: a simulated flake.
test('flaky: a slow load now and then', async ({ page }, info) => {
await page.setContent('<h1>Welcome</h1>');
expect((info.repeatEachIndex + info.retry) % 3, 'simulated slow load').not.toBe(0);
});
// Fails the same way every time: the heading says "Welcome", the test expects "Welcome back".
test('real bug: wrong heading', async ({ page }) => {
await page.setContent('<h1>Welcome</h1>');
await expect(page.locator('h1')).toHaveText('Welcome back', { timeout: 300 });
});
Exécutez-le six fois sans les nouvelles tentatives :
npx playwright test --retries=0 --repeat-each=6
Playwright se termine avec 8 échecs et 4 réussites. Le décompte par test apporte la réponse à la question, et c'est ce que le rapporteur de liste a affiché, ligne par ligne :
flaky: a slow load now and then 4 passed, 2 failed
real bug: wrong heading 0 passed, 6 failed
Exécutez-le maintenant une fois avec deux nouvelles tentatives :
npx playwright test --retries=2
Playwright se termine avec un test dans chaque groupe. Le test instable a échoué lors de sa première tentative et a réussi à la tentative #1. Le véritable bug a échoué lors des trois tentatives.
1 failed
bug-or-flaky.spec.js:10:1 › real bug: wrong heading
1 flaky
bug-or-flaky.spec.js:4:1 › flaky: a slow load now and then
Une nouvelle tentative réussie signifie-t-elle que l'application fonctionne correctement ?
Non. Une nouvelle tentative qui réussit vous indique simplement que les tentatives n'ont pas donné le même résultat, rien de plus. Si l'exécution passe au vert et que personne ne regarde, un défaut intermittent dans l'application, tel qu'une situation de concurrence, des données partagées ou une dépendance lente, devient invisible, et ce sont là parmi les défauts les plus coûteux à identifier. Considérez un résultat instable comme une constatation, et non comme un succès à ignorer, et ne présumez pas que le problème provient du test.
Que fait Nexus Studio de chaque résultat ?
Nexus Studio enregistre chaque tentative et attribue au résultat son propre verdict, de sorte qu'une nouvelle tentative ne transforme jamais un défaut en une simple exécution verte.
- FLAKY : le test a échoué, puis une nouvelle tentative a réussi, sans que rien n'ait été réparé. Il se termine avec le code 0, le build n'est donc pas interrompu, et le rapport ainsi que l'Historique signalent la réserve.
- BREACHED : le test a échoué lors d'une seule tentative, et aucun modèle d'environnement ou de banc de test n'explique l'erreur. Il se termine avec le code 1.
- BREACHED_FLAKY : le test a échoué lors de sa dernière tentative après un nouvel essai préalable, et aucun modèle d'environnement ne l'explique. Il se termine avec le code 1. Comparez les tentatives avant d'ouvrir un ticket de bug.
L'Historique conserve une ligne par exécution de chaque test, de sorte qu'un test qui passe au vert, au rouge puis à nouveau au vert apparaît comme une tendance au lieu de disparaître dans les réexécutions. Le guide des tests instables répertorie les fichiers générés par chaque verdict.
Quelles sont les limites ?
- L'instabilité dans l'exemple est simulée par des calculs arithmétiques afin de pouvoir se répéter. Une véritable instabilité a une cause, et l'identifier reste un travail humain.
- Six exécutions constituent un examen rapide, pas des statistiques. Un échec qui survient une fois sur cinquante exécutions peut très bien réussir six fois de suite.
- Un échec à chaque exécution n'est pas toujours un bug dans votre application : un réseau lent, une page de blocage ou un navigateur figé font également échouer les tests. Le guide des faux échecs vous montre comment faire la différence.
- Lorsque les nouvelles tentatives sont désactivées, un échec intermittent dans Nexus Studio est qualifié de BREACHED, car seule une nouvelle tentative permet de distinguer FLAKY d'un simple échec. La classification analyse le texte de l'erreur, ouvrez donc metadata.json lorsqu'un verdict vous surprend.
Où puis-je le constater ?
Le guide des verdicts explique dans quel ordre le moteur détermine l'ensemble des 14 verdicts, et la page Evidence suit un test ayant échoué à travers chaque fichier qu'il génère. La version d'essai de 30 jours exécute le même moteur sur vos propres tests.