🧱 Locator vs ElementHandle : la différence fondamentale
| Locator | ElementHandle | |
|---|---|---|
| Type | Objet Playwright “haut niveau” | Représentation directe du DOM |
| Recherche | Paresseuse (lazy) → évalue le sélecteur à chaque action | Évaluée immédiatement |
| Attente auto (auto-wait) | ✅ Oui (existence, visibilité, stabilité) | ❌ Non |
| Null possible | ❌ Non | ✅ Oui |
| Recommandé pour les tests E2E | ✅ Oui (toujours) | ⚠️ Rarement |
🧩 Comment obtenir un ElementHandle à partir d’un Locator
// Méthode à utiliser :
const handle = await locator.elementHandle();
// Exemple :
const buttonLocator = page.getByRole('button', { name: 'Envoyer' });
const buttonHandle = await buttonLocator.elementHandle();
if (buttonHandle) {
const box = await buttonHandle.boundingBox();
console.log('Position du bouton :', box);
}
// 🟡 Note :
// Si l’élément n’existe pas au moment de l’appel, elementHandle() retournera null.
// Aucune attente automatique : c’est un “snapshot” immédiat du DOM.⚠️ 3. Pourquoi ElementHandle est rarement nécessaire ?
Dans 95 % des cas, on ne veut pas d’un ElementHandle car :
- On perd les auto-waits (attente automatique que l’élément apparaisse ou devienne stable),
- On s’expose à des erreurs comme :
Error: Element is not attached to the DOM anymore
Le Locator, lui, réévalue le sélecteur à chaque action — il reste donc résilient aux changements du DOM.
Par exemple, après un re-render React, ton Locator fonctionne toujours, ton ElementHandle devient invalide.
🧠 Cas où un ElementHandle est utile malgré tout
Cas légitimes (mais avancés) :
1. Exécuter du code JavaScript directement sur le nœud DOM :
const handle = await page.getByTestId('map').elementHandle();
await handle.evaluate(el => el.scrollIntoView());2. Mesurer la position / taille / style d’un élément :
const box = await handle.boundingBox();
3. Capturer un screenshot précis d’un élément :
await handle.screenshot({ path: 'button.png' });4. Manipulations bas niveau (drag, input, canvas, etc.)
— mais Playwright fournit souvent des helpers plus stables (locator.dragTo(), etc.)
5. Recommandation
💡 Toujours privilégier locator() pour toute action ou assertion :
await locator.click(); await expect(locator).toBeVisible();