web-dev-qa-db-ja.com

要素が存在するだけでなく、アクセス可能になるまでSelenium Web Driverを待機させるにはどうすればよいですか?

Webアプリケーションのテストを書いています。一部のコマンドは、表示されているがしばらく使用できないコントロールを含むダイアログボックスを表示します。 (これらはグレー表示になっていますが、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'

私が試したコードは次のとおりですが、ボタンが使用可能になる前にボタンを「認識」し、基本的に想定される「待機」を過ぎて課金されます。

コードの代わりに10秒のスリープをコードに詰め込めば、コードは適切に機能しますが、それはく、信頼性が低く、非効率的です。しかし、問題は、「クリック」コマンドがコントロールの利用可能性に先んじて競合していることだけであることを証明しています。

28
Skip Huffman
    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ですべてのアイテムを見つけてから、「disabled」でフィルタリングする必要があることに注意してください。単一の検索パターンを希望していましたが、何ができますか?

13
Skip Huffman

イベントのタイムラインは次のようになると思います。

  1. ページに必要な要素はありません。
  2. 必要な要素が表示されますが、無効になっています:
    <input type="button" id="createFolderCreateBtn" disabled="disabled" />
  3. 必要な要素が有効になります:
    <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'

更新:
実際のウェブドライバーで同じものを貼り付けます。
これが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 />
17

私はこれらの線に沿って何かがうまくいくと思う:

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)]")))
1
Milan Cermak

ここには素晴らしい回答がいくつか投稿されていますが、解決策を追加すると思いました。明示的な待機などは、Seleniumでのテストで使用するのに最適な関数です。ただし、明示的な待機は、一度しか設定できない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#で記述されていますが、適応させるのはそれほど難しくありません。お役に立てれば。

0
newITguy