Selenium element not interactable : causes et correctifs
Diagnostiquez element not interactable dans Selenium : commande, doublons cachés, cadre, état du contrôle et obstruction. Avec un cas de test Python local.
BotBrowser Team
Vous voulez la documentation structurée pour Démarrage ?
Cet article fait partie de la bibliothèque éditoriale. Pour les étapes de configuration, la référence et les mises à jour continues, passez directement à la section docs.
Une erreur element not interactable de Selenium signifie que l'élément sélectionné ne peut pas recevoir l'interaction demandée dans son état actuel. Commencez par la commande en échec et le nœud réellement trouvé : un doublon caché, un champ qui ne peut pas recevoir le focus clavier et un clic bloqué par un autre élément exigent des corrections différentes. BotBrowser configure un environnement de navigateur déclaré pour reproduire les différences de mise en page ; il ne corrige pas les sélecteurs et ne garantit pas que l'application soit prête.
Résumé
- Conservez ensemble la classe d'exception et la commande.
ElementNotInteractableException,ElementClickInterceptedExceptionetInvalidElementStateExceptiondécrivent des échecs différents. - Comptez les correspondances dans le document et le composant voulus avant d'ajouter une attente ; Selenium peut renvoyer le premier doublon caché.
element_to_be_clickablevérifie la visibilité et l'état activé, pas si une superposition couvre le point de clic.- Utilisez la véritable condition de disponibilité de l'application et vérifiez la valeur obtenue ou l'état enregistré. Une commande qui revient sans erreur ne prouve pas que l'action a fonctionné.
Sommaire
- Classer la commande en échec avant de changer les attentes
- Reproduire un doublon caché sur une page locale
- Suivre le diagnostic de l'identité au résultat
- Corriger la disponibilité sans masquer les défauts applicatifs
- Conclusion pratique
Classer la commande en échec avant de changer les attentes
Le protocole WebDriver définit l'interaction avec les éléments en fonction de l'opération, pas seulement de l'existence d'un nœud DOM. Trouver un élément établit une référence ; cela ne prouve pas qu'il s'agit du contrôle voulu ni qu'il peut recevoir un clic. Conservez la première ligne de l'erreur, l'appel en échec et la chaîne de sélecteurs avant de relancer le test sur un autre état de la page.
| Commande et observation | Premier point à inspecter | Ce que cela ne prouve pas |
|---|---|---|
click() lève ElementNotInteractableException | Cible cachée, géométrie et possibilité de l'amener à l'écran par défilement | Que le sélecteur a trouvé le bon contrôle |
click() lève ElementClickInterceptedException | L'élément qui couvre le centre visible de la cible | Que la cible nécessite un autre sélecteur |
send_keys() lève ElementNotInteractableException | La possibilité d'interagir au clavier avec l'élément sélectionné | Que le texte doit être saisi dans un conteneur voisin |
clear() lève InvalidElementStateException | Le caractère modifiable de l'élément, y compris son état readonly | Qu'un élément activé est nécessairement modifiable |
| Une commande revient, mais rien ne change | La valeur du champ ou le résultat défini par l'application | Que l'absence d'exception prouve la réussite |
Pour un élément ordinaire, l'algorithme Element Click fait défiler le conteneur de l'élément pour le rendre visible et vérifie la cible du clic. Une cible qui reste hors écran et un centre masqué suivent des branches d'erreur différentes. Les contrôles particuliers, comme les options, ont leur propre traitement : une classification des erreurs ne doit donc pas être considérée comme une implémentation complète de chaque contrôle HTML. Utilisez l'exception observée sur la commande en échec plutôt que de renommer tous les échecs de clic not interactable.
L'algorithme Element Send Keys vérifie la possibilité d'interaction au clavier, avec un comportement distinct pour les champs de fichiers. Un <div> visuellement similaire à côté d'un véritable <input> n'est pas automatiquement un champ de texte. L'algorithme Element Clear vérifie le caractère modifiable. Par conséquent, is_enabled() seul ne permet pas de déterminer si clear() est valide sur un champ readonly. Gardez des vérifications propres à chaque commande plutôt que de construire un booléen générique de disponibilité.
Conserver les preuves de l'échec initial
Consignez la version de la liaison Selenium du langage, les versions du navigateur et du pilote, l'identité du document ou du cadre, le sélecteur, le nombre de correspondances et une capture à l'étape en échec. Enregistrez un petit ensemble d'attributs sûrs plutôt qu'une page complète contenant des identifiants ou des données clients. Une capture montre la fenêtre affichée ; elle ne prouve pas lequel de deux nœuds correspondants find_element() a renvoyé. Conservez avec elle l'ID, la balise et les états affiché et activé du nœud sélectionné.
Si l'échec est intermittent, comparez les preuves avant et après la transition de l'application. Interroger la page courante après avoir fermé manuellement une fenêtre modale renseigne sur l'état corrigé, pas sur l'état en échec. Conservez l'ElementClickInterceptedException initiale et les détails de l'obstruction, puis cherchez quelle transition de l'application aurait dû supprimer cette obstruction. Le lancement du navigateur et le raccordement du profil sont des prérequis distincts traités dans l'intégration des profils avec Selenium ; un pilote connecté ne choisit pas le bon formulaire.
Reproduire un doublon caché sur une page locale
Créez un environnement virtuel Python, installez Selenium avec python -m pip install selenium, puis enregistrez le code suivant dans interactable.py. Avec une installation locale de Chrome prise en charge, webdriver.Chrome() utilise la gestion des pilotes de Selenium. La préparation initiale peut nécessiter un accès réseau pour obtenir un pilote ; le document de test lui-même est une page data: intégrée qui ne contacte aucun site cible. Dans un environnement hors ligne, fournissez un pilote compatible par la configuration Service de Selenium plutôt que de dépendre d'un téléchargement pendant le test.
from urllib.parse import quote
from selenium import webdriver
from selenium.common.exceptions import ElementNotInteractableException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
HTML = """
<!doctype html><meta charset="utf-8">
<button class="save" style="display:none">Save</button>
<form id="editor" onsubmit="return false">
<label>Name <input id="name"></label>
<button class="save" type="button"
onclick="this.form.dataset.saved='yes'">Save</button>
</form>
"""
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--window-size=1280,900")
driver = webdriver.Chrome(options=options)
try:
driver.get("data:text/html;charset=utf-8," + quote(HTML))
candidates = driver.find_elements(By.CSS_SELECTOR, ".save")
assert len(candidates) == 2
assert not candidates[0].is_displayed()
try:
candidates[0].click()
except ElementNotInteractableException:
pass
else:
raise AssertionError("Hidden target unexpectedly accepted a click")
form = driver.find_element(By.ID, "editor")
intended = form.find_elements(By.CSS_SELECTOR, "button.save")
assert len(intended) == 1
intended[0].click()
WebDriverWait(driver, 5).until(
lambda d: d.find_element(By.ID, "editor").get_attribute("data-saved") == "yes"
)
print("matches=2 hidden_click=rejected scoped_saved=yes")
finally:
driver.quit()
Exécutez python interactable.py. La sortie attendue est matches=2 hidden_click=rejected scoped_saved=yes. Le premier bouton caché partage volontairement la classe du bouton visible. Un find_element(By.CSS_SELECTOR, ".save") à l'échelle de la page sélectionnerait cette première correspondance, tandis que la requête délimitée identifie le bouton de l'éditeur. Attendre plus longtemps cette première correspondance cachée ne la transformerait pas en contrôle voulu.
L'attribut data-saved du cas de test est un résultat défini par l'application et établi par le gestionnaire du bouton. Un véritable test doit observer l'enregistrement sauvegardé, l'état de confirmation ou le champ modifié qui lui correspond. Ne copiez pas cet attribut précis dans une application qui ne possède pas ce contrat. L'assertion distingue le choix d'un contrôle plausible de la preuve que l'action voulue a eu lieu.
Un cas de test local étendu a été exécuté le 2026-11-11 avec Chrome standard 157.0.8103.79 sur macOS arm64, à l'aide d'un ChromeDriver 157.0.8103.50 de la même compilation. Six cas ont réussi sur 3 sessions de navigateur simultanées. Le clic caché et la saisie dans le champ caché ont levé ElementNotInteractableException ; le bouton couvert a levé ElementClickInterceptedException même après la réussite de la condition de clic. Un bouton désactivé est revenu sans enregistrer. La saisie readonly est revenue sans modifier la valeur, tandis que vider ce champ a levé InvalidElementStateException. Ces observations décrivent une exécution synthétique sur le navigateur standard, pas une exécution de BotBrowser ni une garantie concernant d'autres implémentations de navigateur.
Utiliser l'échec comme contre-exemple
Conservez le doublon caché pendant la validation du sélecteur corrigé. Le retirer ferait réussir le sélecteur large initial sans démontrer une meilleure règle de ciblage. De même, changez l'ordre des contrôles sans rapport dans un cas de test que vous contrôlez et confirmez que la requête corrigée choisit toujours l'éditeur. Un sélecteur qui fonctionne par hasard parce que l'élément voulu arrive en premier reste fragile lorsque le balisage adaptatif ou un nouveau composant modifie l'ordre du document.
Le cas data: isole la sémantique du DOM et des interactions. Il ne couvre pas l'authentification d'un site réel, les requêtes réseau, le rendu du framework, les racines shadow ou les cadres imbriqués. Si le pilote échoue au démarrage avant driver.get(), examinez cette préparation séparément : l'absence d'un exécutable de navigateur ne permet aucune conclusion sur la possibilité d'interagir avec les éléments. Consignez l'utilisation éventuelle d'un binary_location personnalisé ou d'un pilote explicite pour qu'une autre machine puisse reproduire les hypothèses de lancement.
Suivre le diagnostic de l'identité au résultat
Vérifiez d'abord le document sélectionné, puis l'identité du sélecteur, l'état du contrôle, la disponibilité et enfin le résultat de l'application. Cet ordre évite de transformer un problème de mauvais document ou de mauvais élément en un délai toujours plus long. La référence de dépannage des erreurs Selenium distingue plusieurs familles d'exceptions ; préservez ces distinctions dans le compte rendu d'échec destiné à un collègue.
Confirmer le document et le composant courants
Un iframe contient un autre document. Si le contrôle appartient à un cadre, basculez vers ce cadre identifié avant de le localiser ; driver.switch_to.default_content() revient au document principal. Évitez les indices de cadres lorsque des contenus intégrés sans rapport peuvent être insérés avant eux. Un élément absent dans le mauvais document est normalement un échec de recherche, pas la preuve que le contrôle visible refuse l'interaction. Le parcours d'une racine shadow constitue une autre frontière et ne doit pas être remplacé par un sélecteur de descendants plus long. Lorsqu'un enfant manque dans un composant, le diagnostic Shadow DOM avec Selenium distingue la recherche de l'hôte et de sa racine des vérifications d'interaction.
Dans le bon document, inspectez toutes les correspondances du sélecteur en échec. Plusieurs nœuds renvoyés par find_elements() ne constituent pas en eux-mêmes une exception ; la première correspondance de find_element() peut simplement être mauvaise. Préférez une identité stable de formulaire, de dialogue ou d'enregistrement avant le sélecteur de son descendant. Selenium ne donne pas à un sélecteur CSS large une compréhension automatique du Save qui appartient au processus.
for index, element in enumerate(driver.find_elements(By.CSS_SELECTOR, ".save")):
print({
"index": index,
"tag": element.tag_name,
"id": element.get_attribute("id"),
"displayed": element.is_displayed(),
"enabled": element.is_enabled(),
"rect": element.rect,
})
Ces valeurs sont des instantanés. Un framework peut remplacer un nœud après l'inspection et provoquer ensuite une StaleElementReferenceException ; il faut alors une nouvelle recherche liée à la même identité de composant. Intercepter les références périmées autour de chaque opération et choisir la première nouvelle correspondance peut changer silencieusement la cible. Recherchez de nouveau le formulaire ou l'enregistrement voulu, puis vérifiez qu'il représente toujours le même objet applicatif.
Séparer visibilité, activation et caractère modifiable
is_displayed() et is_enabled() répondent à des questions différentes. Aucun ne signifie que le point de clic est dégagé, et un champ readonly activé n'accepte pas nécessairement les modifications. Inspectez le véritable nœud interactif plutôt qu'un ancêtre mis en forme. Pour un champ, conservez son type, ses propriétés readonly et disabled, sa valeur courante et tout état applicatif qui contrôle la modification.
field = driver.find_element(By.ID, "name")
print({
"tag": field.tag_name,
"type": field.get_attribute("type"),
"readonly": field.get_property("readOnly"),
"disabled": field.get_property("disabled"),
"value": field.get_property("value"),
})
Ne déduisez pas une erreur du seul attribut disabled. Une commande peut revenir sans produire l'action applicative voulue ; vérifiez donc le marqueur métier même en l'absence d'exception. Un champ readonly peut lui aussi conserver sa valeur après une tentative de saisie. Si la modification est volontairement indisponible, suivez la transition de modification prise en charge par l'application ; retirer readonly ou disabled par script change les conditions du test et ne teste plus le parcours de l'utilisateur.
Examiner l'obstruction une fois le bon élément identifié
L'implémentation des conditions attendues de Selenium pour Python implémente element_to_be_clickable à partir de la visibilité et de l'état activé. Son nom ne promet pas de test du point de clic face aux superpositions. Un bouton visible et activé derrière une fenêtre modale peut satisfaire cette condition tout en levant ElementClickInterceptedException au clic. Cette distinction entre le prédicat d'attente et la commande WebDriver suivante est significative.
Utilisez une capture et les détails d'interception de l'erreur pour localiser l'élément qui recouvre la cible. Sur une page que vous contrôlez, document.elementFromPoint() près du centre visible de la cible peut apporter un indice supplémentaire. Considérez-le comme une aide à l'inspection plutôt que comme une réimplémentation de la spécification WebDriver : le rognage, les conteneurs de défilement, les nœuds descendants et les changements de mise en page affectent le point pertinent. Ne classez pas un élément uniquement à partir d'un test de point réalisé après la disparition de la superposition.
Un en-tête fixe peut couvrir le point final du clic même après un défilement manuel. Un voile de chargement peut ne contenir aucun texte visible tout en recevant les événements du pointeur. Si l'application conserve volontairement une fenêtre modale ouverte, fermez-la par son contrôle normal ou choisissez le parcours à l'intérieur de cette fenêtre. Supprimer la superposition avec JavaScript peut aider à isoler une cause dans un cas local, mais ne constitue pas une correction de bout en bout valide du comportement en production.
Corriger la disponibilité sans masquer les défauts applicatifs
Choisissez une attente portant sur l'état qui rend l'action demandée valide. Les stratégies d'attente de Selenium distinguent les conditions explicites des pauses fixes. Une pause ne vérifie pas l'élément sélectionné et n'explique pas pourquoi la page est prête. Évitez de combiner attentes implicites et explicites sans comprendre leur interaction, car les délais de recherche peuvent rendre une expiration explicite plus difficile à interpréter.
Attendre une transition précise
Pour une application que vous contrôlez et qui retire un voile de chargement avant d'activer Save, une attente explicite peut vérifier les deux conditions. Le bloc illustratif suivant suppose ces sélecteurs exacts et que la disparition de #loading-veil constitue le contrat de disponibilité de l'application. Il est distinct du cas local statique, qui ne possède aucun état de chargement.
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
wait.until(EC.invisibility_of_element_located((By.ID, "loading-veil")))
save = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#editor button.save")))
save.click()
wait.until(
lambda d: d.find_element(By.ID, "editor").get_attribute("data-saved") == "yes"
)
L'invisibilité peut aussi être satisfaite lorsque le voile sélectionné est absent. Une faute dans loading-veil peut donc produire une réussite immédiate trompeuse ; validez le localisateur et le modèle d'état applicatif au lieu de traiter un prédicat réussi comme une disponibilité universelle. Si un voile caché intercepte encore l'entrée parce qu'un autre nœud couvre le bouton, le clic suivant reste la vérification significative. L'assertion de résultat doit identifier cette opération, pas une bannière d'enregistrement sans rapport laissée par un test précédent.
Pour les contrôles dont le rendu est renouvelé, préférez une condition fondée sur un localisateur qui recherche l'élément courant plutôt que de conserver une référence périmée datant d'avant la navigation. N'enveloppez pas tout le parcours dans un réessai sans limite. Si le premier clic a envoyé le formulaire mais que la confirmation est arrivée tardivement, le répéter peut créer un enregistrement en double. Diagnostiquez séparément l'action et son résultat, et utilisez l'identité d'opération de l'application lorsque les soumissions en double importent.
L'analyse des attentes Selenium pour des tests stables développe plus largement les conditions de disponibilité et les références périmées. Ici, la classe d'exception détermine la condition pertinente : une mauvaise correspondance cachée exige une correction d'identité, un champ readonly exige une décision sur l'état de modification, et un centre masqué exige une transition de l'obstruction. Remplacer les trois par la même attente de clic dissimule cette distinction.
Séparer l'activation JavaScript d'un clic comparable à celui d'un utilisateur
driver.execute_script("arguments[0].click()", element) invoque l'activation DOM par script. Cela ne prouve pas que WebDriver pouvait faire défiler la page jusqu'à l'élément et cliquer dessus comme cible du pointeur. Un appel par script peut déclencher un gestionnaire sur un contrôle caché et donner l'impression que le test est corrigé alors que l'utilisateur ne peut toujours pas l'atteindre. Utilisez-le uniquement lorsque l'activation par script est elle-même le comportement testé, en explicitant ce périmètre.
De même, définir la valeur d'un champ par JavaScript ne prouve pas que la saisie était possible ni que l'application a traité les mêmes événements. L'état du framework peut différer de la propriété DOM. Préférez l'interaction de modification prise en charge et vérifiez la valeur effectivement acceptée. Si un point d'entrée de test propre à l'application est nécessaire, gardez son test distinct de l'affirmation concernant l'interaction de bout en bout.
Comparer l'environnement après la commande et l'état
Une fenêtre d'affichage différente peut choisir un autre formulaire adaptatif ; les métriques de police peuvent déplacer une bannière fixe sur le bouton ; des changements de navigateur ou de pilote peuvent modifier la reproduction. Conservez les versions du navigateur et du pilote, les dimensions de la fenêtre et l'état de l'application dans le compte rendu d'échec. L'argument de lancement 1280 par 900 du cas de test est une entrée explicite, pas la preuve que tous les systèmes d'exploitation produisent une géométrie intérieure identique ; consignez la fenêtre d'affichage observée lorsque la disposition détermine le résultat.
BotBrowser configure des paramètres d'écran et de police déclarés au moyen de sa référence de configuration des profils, ce qui peut aider à comparer des reproductions dépendant de la mise en page. Il ne rend pas correct le mauvais bouton Save et ne garantit pas que la superposition d'une application ait disparu. La comparaison d'environnement intervient après un sélecteur déterministe et un contrat de disponibilité ; le cas local sur navigateur standard ne fournit aucune preuve d'empreinte BotBrowser ni de service distant.
Questions fréquentes
Element not clickable désigne-t-il la même erreur ?
Conservez la véritable classe d'exception. ElementClickInterceptedException indique une cible de clic masquée ; ElementNotInteractableException relève d'une autre branche d'interaction. Un compte rendu informel disant not clickable peut désigner l'une ou l'autre, ou une expiration ; obtenez donc la première ligne d'erreur et la commande avant de choisir une correction.
Passer de Python à Java ou C# résout-il le problème ?
Changer de langage ne détermine pas le nœud DOM voulu et ne supprime pas une superposition. La syntaxe de liaison et la présentation des noms d'exception peuvent varier, mais la commande WebDriver et l'état applicatif restent le point de départ du diagnostic. Consignez les versions de la liaison et du pilote lorsque vous comparez les implémentations.
Faut-il allonger l'attente explicite pour chaque échec ?
Seul un état censé changer nécessite une attente. Une correspondance de modèle cachée en permanence, un champ volontairement readonly et un mauvais cadre nécessitent un autre choix de ciblage ou de parcours. Une expiration doit indiquer la condition en échec plutôt que la masquer derrière un message de réessai générique.
Sources
- W3C WebDriver : interaction et commandes d'éléments
- Selenium : dépannage des erreurs
- Selenium : stratégies d'attente
- Selenium Python : source des conditions attendues
- BotBrowser : configuration des profils
Conclusion pratique
Commencez par la commande en échec, vérifiez le document et le nœud sélectionnés, puis testez l'état qui rend l'opération valide. Gardez le doublon caché dans la reproduction locale et prouvez que le bouton à portée délimitée modifie data-saved. Pour une application réelle, conservez une assertion de résultat tout aussi précise avant de déclarer l'interaction corrigée.
Cet article fait partie du guide : Débuter avec l'automatisation du navigateur : carte initiale
Articles Connexes
Playwright strict mode violation : corriger les doublons
DémarrageAttentes Selenium WebDriver pour des tests stables
DémarrageSelenium Shadow DOM : recherches et racines détachées
DémarrageScraping avec Selenium : capacités et relevés
DémarrageIntégrer un profil de navigateur avec Selenium
DémarrageTests d’accessibilité de l’automatisation du navigateur
Exécutez la même vérification dans BotBrowser
Chargez un profil, gardez dans le navigateur les signaux que vous venez de lire, puis confirmez le résultat sur votre propre machine avant le déploiement.