python - select_by_value - ¿Cómo puedo obtener Selenium Web Driver para esperar que un elemento sea accesible, no solo presente?
selenium webdriver python (4)
Creo que algo así también debería funcionar:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
browser = webdriver.Firefox()
wait = WebDriverWait(browser, 30)
wait.until(expected_conditions.presence_of_element_located((By.XPATH, "//*[@id=''createFolderCreateBrn'' and not(@disabled)]")))
Estoy escribiendo pruebas para una aplicación web. Algunos comandos abren cuadros de diálogo que tienen controles visibles, pero que no están disponibles por unos momentos. (Están en gris, pero webdriver todavía los ve como visibles).
¿Cómo puedo decirle a Selenium que espere que el elemento sea realmente accesible y no solo visible?
try:
print "about to look for element"
element = WebDriverWait(driver, 10).until(lambda driver : driver.find_element_by_id("createFolderCreateBtn"))
print "still looking?"
finally: print ''yowp''
Aquí está el código que he intentado, pero "ve" el botón antes de que se pueda usar y, básicamente, se carga justo después de la supuesta "espera".
Tenga en cuenta que puedo rellenar diez segundos con el código en lugar de esto y el código funcionará correctamente, pero eso es feo, poco confiable e ineficiente. Pero demuestra que el problema es solo que el comando "clic" está corriendo antes que la disponibilidad de los controles.
Supongo que la línea de tiempo de los eventos es la siguiente:
- no hay elementos necesarios en la página.
- el elemento necesario aparece, pero está deshabilitado:
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
- el elemento necesario se habilita:
<input type="button" id="createFolderCreateBtn" />
Actualmente estás buscando elemento por id, y encuentras uno en el paso 2, que es anterior a lo que necesitas. Lo que debes hacer es buscarlo por xpath:
//input[@id="createFolderCreateBtn" and not(@disabled)]
Aquí está la diferencia:
from lxml import etree
html = """
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />
"""
tree = etree.fromstring(html, parser=etree.HTMLParser())
tree.xpath(''//input[@id="createFolderCreateBtn"]'')
# returns both elements:
# [<Element input at 102a73680>, <Element input at 102a73578>]
tree.xpath(''//input[@id="createFolderCreateBtn" and not(@disabled)]'')
# returns single element:
# [<Element input at 102a73578>]
Para concluir, aquí está tu código fijo:
try:
print "about to look for element"
element_xpath = ''//input[@id="createFolderCreateBtn" and not(@disabled)]''
element = WebDriverWait(driver, 10).until(
lambda driver : driver.find_element_by_xpath(element_xpath)
)
print "still looking?"
finally:
print ''yowp''
ACTUALIZAR:
Repasting lo mismo con el webdriver real.
Aquí está el código de la página example.html
:
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />
Aquí está la sesión de ipython:
In [1]: from selenium.webdriver import Firefox
In [2]: browser = Firefox()
In [3]: browser.get(''file:///tmp/example.html'')
In [4]: browser.find_elements_by_xpath(''//input[@id="createFolderCreateBtn"]'')
Out[4]:
[<selenium.webdriver.remote.webelement.WebElement at 0x103f75110>,
<selenium.webdriver.remote.webelement.WebElement at 0x103f75150>]
In [5]: browser.find_elements_by_xpath(''//input[@id="createFolderCreateBtn" and not(@disabled)]'')
Out[5]:
[<selenium.webdriver.remote.webelement.WebElement at 0x103f75290>]
ACTUALIZACIÓN 2:
Funciona con esto también:
<input type="button" id="createFolderCreateBtn" disabled />
Ya hay algunas excelentes respuestas publicadas aquí, pero pensé que agregaría mi solución. La espera explícita, etc. son excelentes funciones para usar en las pruebas con selenio. Sin embargo, esperar explícitamente simplemente realiza la función de un Thread.Sleep()
que solo puede establecer una vez. La función siguiente es lo que solía "afeitarme" unos minutos. Espera hasta que el elemento sea "accesible".
//ALTERNATIVE FOR THREAD.SLEEP
public static class Wait
{
//public static void wait(this IWebDriver driver, List<IWebElement> IWebElementLIst)
public static void wait(this IWebDriver driver, By bylocator)
{
bool elementPresent = IsPresent.isPresent(driver, bylocator);
while (elementPresent != true)
{
Thread.Sleep(1000);
elementPresent = IsPresent.isPresent(driver, bylocator);
}
}
}
Está en C #, pero adaptarlo no sería tan difícil. Espero que esto ayude.
print time.time()
try:
print "about to look for element"
def find(driver):
e = driver.find_element_by_id("createFolderCreateBtn")
if (e.get_attribute("disabled")==''true''):
return False
return e
element = WebDriverWait(driver, 10).until(find)
print "still looking?"
finally: print ''yowp''
print "ok, left the loop"
print time.time()
Aquí es con lo que terminamos. (Gracias a lukeis y RossPatterson.) Tenga en cuenta que teníamos que encontrar todos los elementos por id y luego filtrar por "deshabilitado". Hubiera preferido un patrón de búsqueda único, pero ¿qué puedes hacer?