Подтвердить что ты не робот

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

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

Как я могу сказать, что 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'

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

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

4b9b3361

Ответ 1

    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.) Обратите внимание, что нам нужно было найти все элементы по id, а затем отфильтровать "отключено". Я бы предпочел один шаблон поиска, но что вы можете сделать?

Ответ 2

Я предполагаю, что временная шкала событий будет выглядеть следующим образом:

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

В настоящее время вы ищете элемент по id, и вы найдете его на шаге 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 />

Ответ 3

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

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

        }

    }

}

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