09.03.07 — Skills Refactor#

Skills qui refactor la base de tests automatisés existante.

Listing (potentiellement non exhaustif)#

SkillCible
refactor-fragmentationDRY selon préférence utilisateur
introduce-pom-retriesRetries internes aux POMs, avec dédoublement (first-try + with-retries)

refactor-fragmentation#

input  : la base de tests
output : suggestions de refactor DRY :
            - blocs répétés dans 3+ scénarios → extract en fragment
            - connectors quasi-identiques → extract un connector paramétré
            - séquences de log+screenshot répétées → extract un helper
         + recommandation au cas par cas

CLAUDE.md :

When to extract a fragment

  • Don’t extract preemptively. Two scenarios sharing 3 acts is a coincidence. Wait for 3+ scenarios with the same block.
  • The block must be a precondition/postcondition, not the focus of any test. valid_login.py does not use the login fragment — login is the test there, and uses log_and_screenshot for the meaningful page transition.
  • Unhappy-path login tests stay self-contained. failed_logins and unauthenticated_history_access don’t use the fragment — they must stay independent of demo-user state.
  1. Quantité : 3+ scénarios avec le même bloc.
  2. Rôle : pré/postcondition, pas le focus du test.
  3. Indépendance : tests unhappy-path doivent rester self-contained.

refactor-fragmentation applique ces critères et suggère (sans appliquer).

introduce-pom-retries#

input  : un connector qui exerce une action flaky (par exemple click un bouton qui peut fail intermittemment)
output : refactor en :
            1. méthode POM `<action>` sans retry (single try)
            2. méthode POM `<action>_with_retries(retries: int, logger: ILogger)` qui retry intern
            3. connectors duaux :
                - `<action>` : appelle POM `<action>`
                - `<action>_with_retries(retries, logger)` : appelle POM `<action>_with_retries`
            4. scénarios mis à jour pour utiliser la variante appropriée

C’est ce pattern qu’on voit dans ocarina-example/lib/connectors/test_steps/actions/dashboard_login.py :

def login_without_otp(creds: ImmutableCredentials):
    def unwrapped(p: DashboardLoginPage) -> DashboardLoginPage:
        return p.login_without_otp(creds)
    return unwrapped


def login_without_otp_and_with_retries(
    creds: ImmutableCredentials, retries: int, *, logger: ILogger
):
    def unwrapped(p: DashboardLoginPage) -> DashboardLoginPage:
        return p.login_without_otp_and_with_retries(creds, retries, logger=logger)
    return unwrapped

Deux connectors. Le scénario choisit selon le besoin :

  • Cas happy path : login_without_otp_and_with_retries (le useAuth à 10% de raté force le retry).
  • Cas unhappy path (« login avec mauvais mdp ») : login_without_otp (on veut que l’échec se voie, sans retry).

Pourquoi dédoubler#

Sans dédoublementAvec dédoublement
Une seule méthode login(...), toujours avec retryLes tests qui veulent voir un fail immédiat sont brouillés par les retries
Pas de différenciation happy / unhappyDifférenciation claire
Tests fragiles si on enlève le retryTests robustes : la couverture de test est préservée, un test complémentaire visant à ne pas tolérer la flakiness permet de continuer de la tracer sur le côté

« Retries au POM, pas au scénario »#

Holy Book (chapitre « Premiers obstacles du monde réel ») :

Aléas de pas de test#

Pensant avoir laissé derrière moi ce genre de désagréments, j’ai changé de crémerie… pour y découvrir des formulaires instables et des systèmes d’authentification qui fonctionnaient une fois sur deux.

Face à cela, la réponse d’Ocarina est différente : on délègue la responsabilité au POM.

VarianteAvantageInconvénient
Retry au framework (transient_errors)Transparent, approprié en cas de flakiness impossible à vraiment isolerRe-joue tout le test, pas juste l’action flaky
Retry au niveau du POMGranulaire + placé dans une méthode bien nommée — 

Discipline transversale#

  • Analyser des patterns dans la base.
  • Suggérer des refactors.
  • Ne pas immédiatement appliquer sauf si instruction explicite.
  • Respecter les règles d’extraction.