Démonstration de patterns anti-flaky : anti-patterns courants qui rendent une suite de tests instable, et leur correction.
Cible de test : the-internet.herokuapp.com — site de démonstration public conçu spécifiquement pour illustrer des comportements asynchrones (chargements dynamiques, éléments activés après délai).
Une suite de tests "flaky" (instable) échoue de façon aléatoire, sans lien avec un vrai bug applicatif — souvent à cause d'hypothèses de timing fragiles. Ce repo illustre, sur des cas concrets et reproductibles, comment identifier et corriger ces anti-patterns.
Chaque scénario est démontré en deux versions :
before/: la version instable (anti-pattern), volontairement fragileafter/: la version fiabilisée, qui exploite les mécanismes natifs de Cypress plutôt que des attentes arbitraires
Cypress · TypeScript
qa-flaky-tests-patterns/
├── cypress/
│ ├── e2e/
│ │ ├── before/
│ │ │ ├── dynamic-loading.cy.ts # cy.wait() fixe → flaky selon la charge
│ │ │ ├── dynamic-controls.cy.ts # interaction avant fin d'activation → race condition
│ │ │ └── retry-on-transient-error.cy.ts # aucun retry → flaky sur erreur transitoire
│ │ └── after/
│ │ ├── dynamic-loading.cy.ts # assertion avec retry natif Cypress
│ │ ├── dynamic-controls.cy.ts # attente explicite de l'état avant interaction
│ │ └── retry-on-transient-error.cy.ts # retry automatique sur erreur 5xx
│ └── support/
│ └── retry.ts # fonction de retry réutilisable, testable en isolation
├── .github/workflows/
│ └── flaky-tests-demo.yml
├── cypress.config.ts
└── package.json
Avant (anti-pattern) :
cy.contains("Start").click();
cy.wait(3000); // pari sur une durée fixe : flaky si le chargement réel varie
cy.get("#finish").should("be.visible");Après (fiabilisé) :
cy.contains("Start").click();
// Cypress retente automatiquement l'assertion jusqu'à son timeout configuré
cy.get("#finish", { timeout: 10000 }).should("be.visible");Le cy.wait(ms) fixe part du principe qu'un chargement dure toujours le même temps. En réalité, ce temps varie selon la charge serveur, le réseau, ou l'environnement d'exécution (CI vs local). Une assertion Cypress standard (should) retente automatiquement jusqu'à expiration de son timeout — elle s'adapte à la durée réelle au lieu de parier dessus.
Avant (anti-pattern) :
cy.get("#input-example button").click();
cy.get("#input-example input").type("test"); // le champ peut être encore désactivéAprès (fiabilisé) :
cy.get("#input-example button").click();
cy.get("#input-example input").should("not.be.disabled").type("test");Cliquer sur le bouton déclenche une activation asynchrone du champ. Sans attendre explicitement la fin de cette transition, Cypress peut tenter de saisir du texte dans un champ encore désactivé — un comportement qui passe ou échoue selon la rapidité d'exécution de la machine.
Avant (anti-pattern) :
const response = await flakyCall(); // une seule tentative
expect(response.status).to.eq(200); // échoue si le service répond un 502 ponctuelAprès (fiabilisé) :
const response = await requestWithRetry(flakyCall, 3); // retente jusqu'à 3 fois
expect(response.status).to.eq(200); // absorbe les erreurs transitoiresUn service peut répondre ponctuellement une erreur 5xx (surcharge momentanée, redémarrage, latence réseau) sans que cela reflète une vraie régression. requestWithRetry (voir cypress/support/retry.ts) rejoue automatiquement l'appel jusqu'à obtenir une réponse valide ou épuisement des tentatives — ce qui absorbe ces erreurs transitoires sans masquer une vraie panne persistante (si toutes les tentatives échouent, l'échec est bien remonté).
Le pipeline exécute uniquement les versions fiabilisées (after/) comme critère de réussite. Les versions instables (before/) sont aussi exécutées à titre démonstratif, dans un job séparé configuré en continue-on-error: true — leur échec est attendu et n'affecte pas le statut global du pipeline.
npm install
# Reproduire les échecs (versions instables)
npx cypress run --spec "cypress/e2e/before/**/*.cy.ts"
# Vérifier les versions fiabilisées
npx cypress run --spec "cypress/e2e/after/**/*.cy.ts"
Mohamed Touaoua — QA Automaticien Ce projet fait partie de mon portfolio d'automatisation QA.