Selenium element not interactable: causas y soluciones
Diagnostica element not interactable en Selenium: comando, duplicados ocultos, marco, estado del control y obstrucciones. Incluye una prueba local en Python.
BotBrowser Team
Quieres la documentación estructurada de Primeros pasos?
Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.
Un error element not interactable de Selenium significa que el elemento seleccionado no puede recibir la interacción solicitada en su estado actual. Empieza por el comando que falla y el nodo que realmente coincide: un duplicado oculto, un campo que no puede recibir el foco del teclado y un clic bloqueado por otro elemento requieren correcciones distintas. BotBrowser proporciona ajustes declarados del entorno del navegador para reproducir diferencias de diseño; no repara los selectores y no garantiza que la aplicación esté lista.
TL;DR
- Conserva juntos la clase de excepción y el comando.
ElementNotInteractableException,ElementClickInterceptedExceptioneInvalidElementStateExceptiondescriben fallos diferentes. - Cuenta las coincidencias dentro del documento y componente previstos antes de añadir una espera; Selenium puede devolver el primer duplicado oculto.
element_to_be_clickablecomprueba la visibilidad y el estado habilitado, no si una superposición cubre el punto de clic.- Usa la condición real de disponibilidad de la aplicación y verifica el valor resultante o el estado guardado. Que un comando termine sin error no demuestra que la acción haya funcionado.
Contenido
- Clasifica el comando fallido antes de cambiar las esperas
- Reproduce un duplicado oculto en una página local
- Sigue el diagnóstico desde la identidad hasta el resultado
- Corrige la disponibilidad sin ocultar defectos de la aplicación
- Conclusión práctica
Clasifica el comando fallido antes de cambiar las esperas
El protocolo WebDriver define la interacción con elementos en función de la operación, no solo de la existencia de un nodo DOM. Encontrar un elemento correctamente establece una referencia; no demuestra que sea el control previsto ni que pueda recibir un clic. Conserva la primera línea del error, la llamada que falla y la cadena de selectores antes de volver a ejecutar la prueba contra otro estado de página.
| Comando y observación | Qué inspeccionar primero | Qué no demuestra |
|---|---|---|
click() lanza ElementNotInteractableException | Destino oculto, geometría y si el desplazamiento puede llevarlo a la vista | Que el selector haya encontrado el control correcto |
click() lanza ElementClickInterceptedException | El elemento que cubre el centro del destino dentro de la ventana | Que el destino necesite otro selector |
send_keys() lanza ElementNotInteractableException | Si el elemento seleccionado permite interacción con el teclado | Que el texto deba introducirse en un contenedor cercano |
clear() lanza InvalidElementStateException | Si el elemento seleccionado es editable, incluido su estado readonly | Que un elemento habilitado tenga que ser editable |
| Un comando termina, pero nada cambia | El valor del campo o el resultado definido por la aplicación | Que la ausencia de excepción demuestre el éxito |
Para un elemento normal, el algoritmo Element Click desplaza el contenedor del elemento hasta hacerlo visible y comprueba el destino del clic. Un destino que sigue fuera de la vista y un centro tapado siguen ramas de error distintas. Los controles especiales, como las opciones, tienen su propio tratamiento, por lo que una clasificación de errores no debe considerarse una implementación completa de todos los controles HTML. Usa la excepción observada en el comando fallido en lugar de llamar not interactable a cualquier fallo de clic.
El algoritmo Element Send Keys comprueba la posibilidad de interacción mediante teclado y trata por separado los campos de archivos. Un <div> visualmente parecido junto a un <input> real no se convierte automáticamente en un campo de texto. El algoritmo Element Clear comprueba la editabilidad. Por tanto, is_enabled() por sí solo no determina si clear() es válido en un campo readonly. Mantén comprobaciones específicas de cada comando en lugar de crear un único booleano genérico de disponibilidad.
Guarda la evidencia del fallo original
Registra la versión del enlace de Selenium para el lenguaje, las versiones del navegador y del controlador, la identidad del documento o marco, el selector, el número de coincidencias y una captura en el paso que falla. Registra un conjunto reducido de atributos seguros en lugar de una página completa con credenciales o datos de clientes. Una captura muestra la ventana renderizada; no demuestra cuál de dos nodos coincidentes devolvió find_element(). Conserva junto a ella el ID, la etiqueta y los estados mostrado y habilitado del nodo seleccionado.
Si el fallo es intermitente, compara la evidencia anterior y posterior a la transición de la aplicación. Consultar la página activa después de cerrar manualmente un modal aporta evidencia del estado corregido, no del estado fallido. Conserva la ElementClickInterceptedException original y sus detalles de obstrucción, y después investiga qué transición de la aplicación debería haber eliminado esa obstrucción. El arranque del navegador y la conexión del perfil son requisitos previos distintos que cubre la integración de perfiles con Selenium; un controlador conectado no selecciona el formulario correcto.
Reproduce un duplicado oculto en una página local
Crea un entorno virtual de Python, instala Selenium con python -m pip install selenium y guarda lo siguiente como interactable.py. Con una instalación local de Chrome compatible, webdriver.Chrome() usa la gestión de controladores de Selenium. La preparación inicial puede necesitar acceso a la red para obtener un controlador; el documento de prueba es una página data: integrada y no contacta con ningún sitio de destino. En un entorno sin conexión, proporciona un controlador compatible mediante la configuración Service de Selenium en lugar de depender de una descarga durante la prueba.
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()
Ejecuta python interactable.py. La salida esperada es matches=2 hidden_click=rejected scoped_saved=yes. El primer botón oculto comparte deliberadamente la clase del botón visible. Un find_element(By.CSS_SELECTOR, ".save") sobre toda la página seleccionaría esa coincidencia anterior, mientras que la consulta delimitada identifica el botón del editor. Esperar más a la primera coincidencia oculta no la convertiría en el control previsto.
El atributo data-saved de la prueba es un resultado definido por la aplicación y establecido por el manejador del botón. Una prueba real debe observar el registro guardado, el estado de confirmación o el campo modificado que le corresponda. No copies ese atributo concreto a una aplicación que no tenga ese contrato. La aserción distingue entre elegir un control plausible y demostrar que ocurrió la acción prevista.
Una prueba local ampliada se ejecutó el 2026-11-11 con Chrome estándar 157.0.8103.79 en macOS arm64, usando un ChromeDriver 157.0.8103.50 de la misma compilación. Se superaron seis casos en 3 sesiones de navegador simultáneas. El clic en el botón oculto y la escritura en el campo oculto lanzaron ElementNotInteractableException; el botón cubierto lanzó ElementClickInterceptedException incluso después de superar la condición de clic. Un botón deshabilitado terminó sin guardar. La escritura en el campo readonly terminó sin cambiar el valor, mientras que vaciar ese campo lanzó InvalidElementStateException. Estas observaciones describen una ejecución sintética con el navegador estándar, no una ejecución de BotBrowser ni una garantía sobre otras implementaciones de navegador.
Usa el fallo como contraejemplo
Conserva el duplicado oculto mientras validas un selector corregido. Eliminarlo permitiría que el selector amplio original pasara sin demostrar una regla de selección mejor. Del mismo modo, cambia el orden de los controles ajenos en una prueba propia y confirma que la consulta corregida sigue seleccionando el editor. Un selector que funciona por casualidad porque el elemento previsto aparece primero es frágil cuando el marcado adaptable o un componente nuevo cambia el orden del documento.
La prueba data: aísla la semántica del DOM y de la interacción. No cubre la autenticación de un sitio real, las peticiones de red, el renderizado del framework, las raíces shadow ni los marcos anidados. Si el controlador no arranca antes de driver.get(), investiga esa preparación por separado: un ejecutable de navegador no disponible no permite concluir nada sobre la posibilidad de interactuar con elementos. Registra si se utilizó un binary_location personalizado o un controlador explícito para que otra máquina pueda reproducir los supuestos del arranque.
Sigue el diagnóstico desde la identidad hasta el resultado
Comprueba primero el documento seleccionado, después la identidad del selector, el estado del control, la disponibilidad y, por último, el resultado de la aplicación. Este orden evita convertir un problema de documento o elemento equivocado en un tiempo de espera cada vez mayor. La referencia de resolución de errores de Selenium distingue varias familias de excepciones; conserva esas distinciones al redactar un informe de fallo para otra persona del equipo.
Confirma el documento y el componente actuales
Un iframe contiene otro documento. Si el control pertenece a un marco, cambia al marco identificado antes de localizarlo; driver.switch_to.default_content() vuelve al documento principal. Evita los índices de marcos cuando puedan insertarse antes otros elementos incrustados. Un elemento ausente en el documento equivocado normalmente es un fallo de búsqueda, no evidencia de que el control visible no admita interacción. Recorrer una raíz shadow es otra frontera y no debe sustituirse por un selector de descendientes más largo. Si falta un descendiente dentro de un componente, el diagnóstico de Shadow DOM en Selenium recorre la búsqueda del anfitrión y la raíz antes de comprobar la interacción.
Dentro del documento correcto, inspecciona todas las coincidencias del selector que falla. Que find_elements() devuelva varios nodos no es en sí una excepción; la primera coincidencia de find_element() puede ser simplemente incorrecta. Prefiere una identidad estable de formulario, diálogo o registro antes del selector de su descendiente. Selenium no dota a un selector CSS amplio de una comprensión automática de qué Save pertenece al flujo de trabajo.
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,
})
Estos valores son instantáneas. Un framework puede sustituir un nodo después de inspeccionarlo y provocar una StaleElementReferenceException posterior; eso requiere una búsqueda nueva ligada a la misma identidad de componente. Capturar referencias obsoletas alrededor de cada operación y elegir la primera coincidencia nueva puede cambiar silenciosamente el destino. Vuelve a obtener el formulario o registro previsto y verifica que siga representando el mismo objeto de la aplicación.
Separa visibilidad, estado habilitado y editabilidad
is_displayed() e is_enabled() responden a preguntas distintas. Ninguna significa que el punto de clic del elemento esté libre de obstáculos, y un campo readonly habilitado no tiene por qué aceptar modificaciones. Inspecciona el nodo interactivo real en lugar de un ancestro con estilos. Para un campo, conserva su type, las propiedades readonly y disabled, el valor actual y cualquier estado de la aplicación que controle la edición.
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"),
})
No deduzcas un error únicamente de un atributo disabled. Un comando puede terminar sin producir la acción prevista en la aplicación, por lo que debes verificar el marcador de negocio aunque no aparezca ninguna excepción. Un campo readonly también puede conservar su valor tras un intento de escritura. Si la edición está desactivada deliberadamente, sigue la transición de edición admitida por la aplicación; quitar readonly o disabled mediante un script cambia las condiciones de prueba y deja de probar el flujo del usuario.
Inspecciona la obstrucción después de identificar el elemento correcto
La implementación de condiciones esperadas de Selenium para Python implementa element_to_be_clickable mediante la visibilidad y el estado habilitado. El nombre no promete una comprobación de qué elemento recibe el puntero frente a las superposiciones. Un botón visible y habilitado detrás de un modal puede cumplir esa condición y aun así lanzar ElementClickInterceptedException al pulsarlo. Es una distinción significativa entre el predicado de espera y el comando WebDriver posterior.
Usa una captura y los detalles de intercepción del error para localizar el elemento que cubre el destino. En una página propia, document.elementFromPoint() cerca del centro del destino dentro de la ventana puede aportar evidencia adicional. Trátalo como una ayuda de inspección y no como una nueva implementación de la especificación WebDriver: los recortes, los contenedores de desplazamiento, los nodos descendientes y los cambios de diseño afectan al punto pertinente. No clasifiques un elemento únicamente a partir de una comprobación de destino realizada después de que la superposición haya desaparecido.
Una cabecera fija puede cubrir el punto final de clic incluso después de desplazar la página manualmente. Una capa de carga puede no tener texto visible y seguir recibiendo la entrada del puntero. Si la aplicación mantiene un modal abierto deliberadamente, ciérralo mediante su control normal o elige el flujo dentro de ese modal. Eliminar la superposición con JavaScript puede ayudar a aislar una causa en una prueba local, pero no es una corrección integral válida del comportamiento en producción.
Corrige la disponibilidad sin ocultar defectos de la aplicación
Elige una espera para el estado que hace válida la acción solicitada. Las estrategias de espera de Selenium distinguen las condiciones explícitas de las pausas fijas. Una pausa no comprueba el elemento seleccionado ni explica por qué la página está lista. Evita combinar esperas implícitas y explícitas sin entender su interacción, porque los retrasos de búsqueda pueden dificultar la interpretación de un tiempo de espera explícito.
Espera una transición concreta
Para una aplicación propia que elimina una capa de carga antes de habilitar Save, una espera explícita puede inspeccionar ambas condiciones. El bloque ilustrativo siguiente presupone esos selectores exactos y que la desaparición de #loading-veil es el contrato de disponibilidad de la aplicación. Es independiente de la prueba local estática, que no tiene estado de carga.
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"
)
La invisibilidad también puede cumplirse cuando la capa seleccionada está ausente. Por tanto, una errata en loading-veil puede producir un éxito inmediato engañoso; valida el localizador y el modelo de estados de la aplicación en lugar de tratar un predicado superado como disponibilidad universal. Si una capa oculta sigue interceptando la entrada porque otro nodo cubre el botón, el clic posterior sigue siendo la comprobación significativa. La aserción del resultado debe identificar esta operación, no un aviso de guardado ajeno que dejó una prueba anterior.
Para controles renderizados de nuevo, prefiere una condición basada en localizadores que vuelva a obtener el elemento actual antes que conservar una referencia obsoleta anterior a la navegación. No envuelvas todo el flujo en un reintento sin límite. Si el primer clic envió el formulario, pero la confirmación llegó tarde, repetirlo puede crear un registro duplicado. Diagnostica la acción y su resultado por separado y usa la identidad de operación de la aplicación cuando importen los envíos duplicados.
El análisis de esperas de Selenium y pruebas estables desarrolla con más amplitud las condiciones de disponibilidad y las referencias obsoletas. Aquí, la clase de excepción decide qué condición es pertinente: una coincidencia oculta incorrecta necesita una corrección de identidad, un campo readonly necesita una decisión de estado de edición y un centro tapado necesita una transición de obstrucción. Sustituir las tres por la misma espera de clic oculta esa distinción.
Separa la activación con JavaScript de un clic similar al del usuario
driver.execute_script("arguments[0].click()", element) invoca la activación DOM mediante un script. No demuestra que WebDriver pudiera desplazarse hasta el elemento y pulsarlo como destino del puntero. Una llamada de script puede activar un manejador en un control oculto y hacer que la prueba parezca corregida mientras el usuario sigue sin poder alcanzarlo. Úsala solo cuando la activación mediante script sea precisamente el comportamiento probado, con ese alcance explícito.
Del mismo modo, establecer el valor de un campo mediante JavaScript no demuestra que fuera posible escribir ni que la aplicación procesara los mismos eventos. El estado del framework puede diferir de la propiedad DOM. Prefiere la interacción de edición admitida y comprueba el valor realmente aceptado. Si es necesario un punto de prueba propio de la aplicación, mantén su prueba separada de la afirmación sobre la interacción de extremo a extremo.
Compara el entorno después del comando y el estado
Otra ventana gráfica puede seleccionar un formulario adaptable diferente; las métricas de fuentes pueden desplazar un aviso fijo sobre el botón; los cambios del navegador o controlador pueden alterar la reproducción. Conserva en el registro del fallo las versiones del navegador y del controlador, las dimensiones de la ventana y el estado de la aplicación. El argumento de arranque 1280 por 900 de la prueba es una entrada explícita, no una demostración de que todos los sistemas operativos produzcan una geometría interior idéntica; registra la ventana gráfica observada cuando el diseño determine el resultado.
BotBrowser proporciona ajustes declarados de pantalla y fuentes mediante su referencia de configuración de perfiles, que pueden ayudar a comparar reproducciones dependientes del diseño. No convierte el botón Save equivocado en el correcto ni garantiza que la superposición de una aplicación haya terminado. La comparación de entornos corresponde a un paso posterior a un selector determinista y un contrato de disponibilidad; la prueba local del navegador estándar no aporta evidencia de huella de BotBrowser ni de servicios remotos.
Preguntas frecuentes
¿Es element not clickable el mismo error?
Conserva la clase real de excepción. ElementClickInterceptedException apunta a un destino de clic tapado; ElementNotInteractableException corresponde a otra rama de interacción. Los informes informales que dicen not clickable pueden referirse a cualquiera de ellos o a un tiempo de espera agotado, así que obtén la primera línea del error y el comando antes de elegir una corrección.
¿Cambiar de Python a Java o C# lo resuelve?
Cambiar de lenguaje no determina el nodo DOM previsto ni elimina una superposición. La sintaxis del enlace y la presentación de los nombres de excepción pueden diferir, pero el comando WebDriver y el estado de la aplicación siguen siendo el punto de partida del diagnóstico. Registra las versiones del enlace y del controlador al comparar implementaciones.
¿Cada fallo necesita una espera explícita más larga?
Solo un estado que se espera que cambie necesita una espera. Una coincidencia de plantilla permanentemente oculta, un campo readonly deliberado y el marco equivocado necesitan otra decisión de selección o de flujo de trabajo. Un tiempo de espera agotado debe indicar qué condición falló en lugar de esconderla tras un mensaje genérico de reintento.
Fuentes
- W3C WebDriver: interacción y comandos de elementos
- Selenium: resolución de errores
- Selenium: estrategias de espera
- Selenium para Python: código de condiciones esperadas
- BotBrowser: configuración de perfiles
Conclusión práctica
Empieza por el comando que falla, verifica el documento y nodo seleccionados y después comprueba el estado que hace válida esa operación. Conserva el duplicado oculto en la reproducción local y demuestra que el botón delimitado cambia data-saved. Para una aplicación activa, conserva una aserción de resultado igual de específica antes de considerar corregida la interacción.
Este artículo forma parte de la guía: Primeros pasos con automatización de navegador: mapa inicial
Artículos Relacionados
Playwright strict mode violation: corregir duplicados
Primeros pasosEsperas de Selenium WebDriver para pruebas estables
Primeros pasosSelenium Shadow DOM: búsquedas y raíces desconectadas
Primeros pasosScraping con Selenium: capacidades y registros
Primeros pasosIntegración de perfiles de navegador con Selenium
Primeros pasosPruebas de accesibilidad con automatización del navegador
Ejecuta la misma comprobación en BotBrowser
Carga un perfil, mantén dentro del navegador las señales que acabas de leer y confirma el resultado en tu propia máquina antes del despliegue.