Как я могу заставить Selenium Web Driver ждать, пока будет доступен элемент, а не только присутствует? - PullRequest
28 голосов
/ 06 февраля 2012

Я пишу тесты для веб-приложения.Некоторые команды открывают диалоговые окна, которые имеют элементы управления, которые видны, но недоступны в течение нескольких минут(Они неактивны, но веб-драйвер по-прежнему видит их видимыми).

Как я могу сказать Selenium ждать, пока элемент будет действительно доступен, а не только видим?

    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'

Вот код, который я пробовал, но он «видит» кнопку до того, как ее можно будет использовать, и в основном заряжается сразу после предполагаемого «ожидания».

Обратите внимание, что я могувместо этого добавьте десять секунд сна в код, и код будет работать правильно, но это уродливо, ненадежно и неэффективно.Но это доказывает, что проблема в том, что команда «щелкнуть» опережает доступность элементов управления.

Ответы [ 4 ]

17 голосов
/ 06 февраля 2012

Я предполагаю, что график событий выглядит так:

  1. на странице нет нужных элементов.
  2. необходимый элемент появляется, но отключен:
    <input type="button" id="createFolderCreateBtn" disabled="disabled" />
  3. необходимый элемент становится активным:
    <input type="button" id="createFolderCreateBtn" />

В настоящее время вы ищете элемент по идентификатору, и вы найдете его на шаге 2, что раньше, чем вам нужно. Что вам нужно сделать, это поиск по xpath:

//input[@id="createFolderCreateBtn" and not(@disabled)]

Вот разница:

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>]

Чтобы подвести итог, вот ваш фиксированный код:

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'

UPDATE:
Воспроизведение то же самое с реальным webdriver.
Вот код страницы example.html:

<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />

Вот сеанс 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>]

ОБНОВЛЕНИЕ 2:

Это работает и с этим:

<input type="button" id="createFolderCreateBtn" disabled />
13 голосов
/ 07 февраля 2012
    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()

Вот чем мы закончили.(Спасибо lukeis и RossPatterson.) Обратите внимание, что нам нужно было найти все элементы по идентификатору, а затем отфильтровать по «отключен».Я бы предпочел один шаблон поиска, но что вы можете сделать?

1 голос
/ 20 февраля 2018

Я думаю, что-то вроде этого должно также работать:

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)]")))
0 голосов
/ 09 августа 2012

Здесь уже есть несколько отличных ответов, но я решил добавить свое решение. Явное ожидание и т. Д. - отличные функции для тестирования с селеном. Однако явное ожидание просто выполняет функцию Thread.Sleep(), которую вы можете установить только один раз. Приведенная ниже функция - это то, что я использовал, чтобы «сбрить» несколько минут. Он ждет, пока элемент не станет «доступным».

    //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); 

        }

    }

}

Это в C #, но адаптировать его было бы не так сложно. Надеюсь это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...