🧱 Locator vs ElementHandle : la différence fondamentale

LocatorElementHandle
TypeObjet Playwright “haut niveau”Représentation directe du DOM
RechercheParesseuse (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();