Bonnes pratiques Playwright
Ce chapitre résume les bonnes pratiques les plus importantes pour écrire et maintenir des tests Playwright, vous aidant à écrire des tests stables et maintenables.
Philosophie des tests
Tester le comportement visible par l'utilisateur
Les tests automatisés doivent vérifier ce que les utilisateurs finaux peuvent voir et avec quoi ils peuvent interagir, plutôt que de vérifier les détails d'implémentation du code.
Par exemple, les tests doivent vérifier que le texte correct est affiché sur la page, que les boutons sont cliquables et que la soumission du formulaire navigue vers la bonne page, plutôt que de vérifier la valeur de retour d'une fonction JavaScript ou la structure interne du DOM.
Exemple
expect(await page.evaluate(() => window.__store.getState().user.name))
.toBe('example');
// Recommandé : tester ce que les utilisateurs voient
await expect(page.getByText('Welcome, example')).toBeVisible();
Isolation des tests
Chaque test doit êtrecomplètement indépendantdes autres tests, et ne pas dépendre de l'état d'un test précédent.
Playwright fournit un contexte indépendant par défaut, mais vous devez également vous assurer que vous ne dépendez pas de l'ordre d'exécution des tests.
Exemple
let createdId;
test('Create resource', async ({ request }) => {
const resp = await request.post('/api/items');
createdId = (await resp.json()).id; // État partagé
});
test('Use created resource', async ({ page }) => {
await page.goto(`/items/${createdId}`); // Dépend du résultat du test précédent
});
// Recommandé : chaque test est autonome
test('Créer et utiliser une ressource', async ({ request, page }) => {
const resp = await request.post('/api/items');
const id = (await resp.json()).id;
await page.goto(`/items/${id}`);
await expect(page.getByText('Détails de la ressource')).toBeVisible();
});
Principes de priorité des localisateurs
Utiliser les localisateurs dans l'ordre recommandé peut améliorer la stabilité des tests.
| Priorité | Méthode | Scénario d'application |
|---|---|---|
| 1 | getByRole() | L'élément a un rôle ARIA clair |
| 2 | getByLabel() | Élément de formulaire associé à une étiquette |
| 3 | getByPlaceholder() | Le champ de saisie a un texte indicatif |
| 4 | getByText() | L'élément a un texte explicite |
| 5 | getByAltText() | L'image a un attribut alt |
| 6 | getByTitle() | L'élément a un attribut title |
| 7 | getByTestId() | Repli |
| 8 | locator() | CSS/XPath, en dernier recours |
Essayez d'éviter d'utiliser les noms de classes CSS comme localisateurs.
Les noms de classes sont susceptibles de changer en raison de la refactorisation des styles, ce qui entraîne des échecs de tests à grande échelle.
Évitez les attentes inutiles
Tirez parti du mécanisme d'attente automatique de Playwright, évitez le codage manuelsleepouwaitForTimeout。
Exemple
await page.waitForTimeout(3000);
await page.getByText('Chargement des données terminé').click();
// Recommandé : s'appuyer sur l'attente automatique et les assertions
await expect(page.getByText('Chargement des données...')).toBeHidden({ timeout: 10000 });
await page.getByText('Chargement des données terminé').click();
Ne testez pas les services tiers
Ne testez que ce que vous pouvez contrôler ; ne dépendez pas de la disponibilité des services tiers.
Exemple
await page.goto('https://www.example.com/');
// La page peut charger Google Analytics, des polices externes, etc.
// Recommandé : intercepter les requêtes tierces, simuler les services externes
await page.route('**/*analytics*', route => route.abort());
await page.route('**/external-api/**', route => {
route.fulfill({ json: { status: 'ok' } });
});
Utilisez expect.soft() pour des assertions souples
Lorsque vous vérifiez plusieurs conditions indépendantes, les assertions souples peuvent signaler tous les échecs d'un coup au lieu de s'arrêter au premier échec.
Exemple
await expect.soft(page.getByLabel('Username')).toBeVisible();
await expect.soft(page.getByLabel('Password')).toBeVisible();
await expect.soft(page.getByLabel('Email')).toBeVisible();
await expect.soft(page.getByRole('button', { name: 'Register' })).toBeEnabled();
// Si plusieurs champs sont manquants, signalez-les tous en même temps
Organiser les fichiers de test de manière raisonnable
| Pratique | Description |
|---|---|
| Diviser les fichiers par module fonctionnel | login.spec.ts、checkout.spec.tswait |
| Utiliser describe pour regrouper | Mettre les tests associés danstest.describe()Moyenne |
| Bien utiliser beforeEach | Extraire les étapes de navigation et de configuration répétées dansbeforeEach |
| Noms de tests descriptifs | De bons noms expliquent « ce qui a été fait » et « ce qui est attendu » |
| Extraire le code commun | Les helpers utilisés dans plus de 3 fichiers doivent être extraits dans un module partagé |
| Ne pas abuser du DRY | 2-3 lignes de répétition sont plus faciles à maintenir qu'une sur-abstraction |
Dépannage courant
Tests instables
Causes et solutions des tests instables :
| Cause | Solution |
|---|---|
| Le délai d'attente codé en dur n'est pas assez long | Utiliser un mécanisme d'attente automatique au lieu d'attentes fixes |
| Dépendre de services tiers | Utiliserroute()Simuler les requêtes externes |
| Les animations provoquent des changements de position des éléments | Dans la configurationanimations: 'disabled' |
| Résidus de données entre les tests | S'assurer que chaque test crée et nettoie les données de manière indépendante |
| Logique liée au temps | Utiliserpage.clockHeure fixe |
Le localisateur ne trouve pas l'élément
Étapes de dépannage :
- Vérifier si l'élément est dans le DOM (utilisez
toBeAttached()plutôt quetoBeVisible()) - Vérifier si l'élément est dans la fenêtre d'affichage
- Vérifier s'il est imbriqué dans une iframe
- Utilisez Pick Locator en mode UI pour vérifier le localisateur
- Vérifier s'il y a plusieurs éléments correspondants (Locator requiert le mode strict par défaut)