web-dev-qa-db-ja.com

Selenium c#Webdriver:要素が表示されるまで待つ

Webドライバが作業を始める前に、要素が存在することを確認したいです。

私はこのようなものを動作させようとしています:

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(By.Id("login"));

私は主に、任意関数の設定方法に苦労しています。

163
AyKarsi

あるいは、暗黙の待機を使用できます。

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

暗黙のうちに待機しているのは、WebDriverがあるエレメントをすぐに使用できない場合にそれらを検索しようとするときに一定時間DOMをポーリングするように指示することです。デフォルト設定は0です。設定されると、WebDriverオブジェクトインスタンスの存続期間中、暗黙的な待機が設定されます。

141
Mike Kwan

暗黙の待機はすべてのFindElement呼び出しで使用されるため、Mike Kwanが提供するソリューションを使用するとテスト全体のパフォーマンスに影響が出る可能性があります。要素が存在しないときにFindElementがすぐに失敗するようにしたい(あなたは不正なページのためのテスト、欠けている要素など)。暗黙的な待機では、これらの操作は例外をスローする前にタイムアウト全体が期限切れになるのを待ちます。デフォルトの暗黙的待機は0秒に設定されています。

FindElement()メソッドにタイムアウト(秒単位)パラメータを追加する、IWebDriverへの小さな拡張メソッドを書きました。一目瞭然です。

public static class WebDriverExtensions
{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }
        return driver.FindElement(by);
    }
}

WebDriverWaitオブジェクトは作成が非常に安価であるためキャッシュに入れませんでした。この拡張機能はさまざまなWebDriverオブジェクトに同時に使用できますが、最終的に必要なときにのみ最適化を行います。

使い方は簡単です。

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost/mypage");
var btn = driver.FindElement(By.CssSelector("#login_button"));
btn.Click();
var employeeLabel = driver.FindElement(By.CssSelector("#VCC_VSL"), 10);
Assert.AreEqual("Employee", employeeLabel.Text);
driver.Close();
251
Loudenvier

また使用することができます

ExpectedConditions.ElementExists

だからあなたはそのような要素の可用性を検索します

new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));

出典

80
Zain Ali

これは、複数の要素を取得するためにも機能する@ Loudenvierのソリューションの変形です。

public static class WebDriverExtensions
{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }
        return driver.FindElement(by);
    }

    public static ReadOnlyCollection<IWebElement> FindElements(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => (drv.FindElements(by).Count > 0) ? drv.FindElements(by) : null);
        }
        return driver.FindElements(by);
    }
}
29
Rn222

Loudenvierのソリューションに触発された、これは前者の特殊化であるIWebDriverだけでなく、すべてのISearchContextオブジェクトのために働く拡張メソッドです。このメソッドは、要素が表示されるまで待つこともサポートしています。

static class WebDriverExtensions
{
    /// <summary>
    /// Find an element, waiting until a timeout is reached if necessary.
    /// </summary>
    /// <param name="context">The search context.</param>
    /// <param name="by">Method to find elements.</param>
    /// <param name="timeout">How many seconds to wait.</param>
    /// <param name="displayed">Require the element to be displayed?</param>
    /// <returns>The found element.</returns>
    public static IWebElement FindElement(this ISearchContext context, By by, uint timeout, bool displayed=false)
    {
        var wait = new DefaultWait<ISearchContext>(context);
        wait.Timeout = TimeSpan.FromSeconds(timeout);
        wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
        return wait.Until(ctx => {
            var elem = ctx.FindElement(by);
            if (displayed && !elem.Displayed)
                return null;

            return elem;
        });
    }
}

使用例

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
var btn = main.FindElement(By.Id("button"));
btn.Click();
var dialog = main.FindElement(By.Id("dialog"), 5, displayed: true);
Assert.AreEqual("My Dialog", dialog.Text);
driver.Close();
16
aknuds1

匿名関数と述語を混同しました。 HERESの小さなヘルパーメソッド:

   WebDriverWait wait;
    private void waitForById(string id) 
    {
        if (wait == null)            
            wait = new WebDriverWait(driver, new TimeSpan(0,0,5));

        //wait.Until(driver);
        wait.Until(d => d.FindElement(By.Id(id)));
    }
9
AyKarsi

あなたはC#でこのようなことを見つけることができます。

これは私がJUnit - Seleniumで使用したものです。

WebDriverWait wait = new WebDriverWait(driver, 100);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));

関連パッケージをインポートする

3
Aditi

Python:

from Selenium import webdriver
from Selenium.webdriver.support import expected_conditions as EC
from Selenium.webdriver.support.ui import WebDriverWait
from Selenium.webdriver.common.by import By

driver.find_element_by_id('someId').click()

WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.ID, 'someAnotherId'))

eCから他の条件を選択することもできますこれを試してみてください。 http://Selenium-python.readthedocs.org/api.html#module-Selenium.webdriver.support.expected_conditions

//wait up to 5 seconds with no minimum for a UI element to be found
WebDriverWait wait = new WebDriverWait(_pagedriver, TimeSpan.FromSeconds(5));
IWebElement title = wait.Until<IWebElement>((d) =>
{
    return d.FindElement(By.ClassName("MainContentHeader"));
});
2
Brian121212

このコードを試してください:

 New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)
2

Selenium IDEでWebドライバ形式を選択した場合、clickAndWaitコマンドは変換されません。これが回避策です。以下に待機行を追加します。現実的には、問題は私のC#コードのこの1行目の前に発生したクリックまたはイベントでした。しかし、実際には、 "By"オブジェクトを参照しているアクションの前に必ずWaitForElementがあることを確認してください。

HTML code:

<a href="http://www.google.com">xxxxx</a>

C#/ NUnitコード:

driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();
2
MacGyver
public bool doesWebElementExist(string linkexist)
{
     try
     {
        driver.FindElement(By.XPath(linkexist));
        return true;
     }
     catch (NoSuchElementException e)
     {
        return false;
     }
}
1
Madhu

私はページ要素の定義とページテストのシナリオを見やすさのためにすでに見つかったIWebElementを使って分離しているので、このようにすることができます:

public static void WaitForElementToBecomeVisibleWithinTimeout(IWebDriver driver, IWebElement element, int timeout)
{
    new WebDriverWait(driver, TimeSpan.FromSeconds(timeout)).Until(ElementIsVisible(element));
}

private static Func<IWebDriver, bool> ElementIsVisible(IWebElement element)
{
    return driver => {
        try
        {
            return element.Displayed;              
        }
        catch(Exception)
        {
            // If element is null, stale or if it cannot be located
            return false;
        }
    };
}
1
Angel_D

明示的な待機

public static  WebDriverWait wait = new WebDriverWait(driver, 60);

例:

wait.until(ExpectedConditions.visibilityOfElementLocated(UiprofileCre.UiaddChangeUserLink));
1
Pavan T

要素が変更されるまであまり長く待ちたくないでしょう。このコードでは、Webドライバは続行する前に最大2秒間待機します。

 
 WebDriverWait wait = new WebDriverWait(ドライバ、TimeSpan.FromMilliseconds(2000)); 
 wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.Name( "html-name"))) ); 
 
1
user3607478

複数のソリューションがすでに投稿されていて、とてもうまくいっています。しかし、万が一他に何かが必要な場合に備えて、私が個人的にSelenium C#で使用している2つの解決策を投稿して、要素が存在するかどうかをテストすることを考えました。応援よろしくお願いします。

public static class IsPresent
{
    public static bool isPresent(this IWebDriver driver, By bylocator)
    {

        bool variable = false;
        try
        {
            IWebElement element = driver.FindElement(bylocator);
            variable = element != null;
        }
       catch (NoSuchElementException){

       }
        return variable; 
    }

}

これが2番目です

    public static class IsPresent2
{
    public static bool isPresent2(this IWebDriver driver, By bylocator)
    {
        bool variable = true; 
        try
        {
            IWebElement element = driver.FindElement(bylocator);

        }
        catch (NoSuchElementException)
        {
            variable = false; 
        }
        return variable; 
    }

}
0
newITguy

Rn222とAknuds1を使用して、単一の要素またはリストを返すISearchContextを使用しました。そして、最小数の要素を指定することができます。

public static class SearchContextExtensions
{
    /// <summary>
    ///     Method that finds an element based on the search parameters within a specified timeout.
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeOutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <returns> The first element found that matches the condition specified</returns>
    public static IWebElement FindElement(this ISearchContext context, By by, uint timeOutInSeconds)
    {
        if (timeOutInSeconds > 0)
        {
            var wait = new DefaultWait<ISearchContext>(context);
            wait.Timeout = TimeSpan.FromSeconds(timeOutInSeconds);
            return wait.Until<IWebElement>(ctx => ctx.FindElement(by));
        }
        return context.FindElement(by);
    }
    /// <summary>
    ///     Method that finds a list of elements based on the search parameters within a specified timeout.
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <returns>A list of all the web elements that match the condition specified</returns>
    public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds)
    {

        if (timeoutInSeconds > 0)
        {
            var wait = new DefaultWait<ISearchContext>(context);
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
            return wait.Until<IReadOnlyCollection<IWebElement>>(ctx => ctx.FindElements(by));
        }
        return context.FindElements(by);
    }
    /// <summary>
    ///     Method that finds a list of elements with the minimum amount specified based on the search parameters within a specified timeout.<br/>
    /// </summary>
    /// <param name="context">The context where this is searched. Required for extension methods</param>
    /// <param name="by">The search parameters that are used to identify the element</param>
    /// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
    /// <param name="minNumberOfElements">
    ///     The minimum number of elements that should meet the criteria before returning the list <para/>
    ///     If this number is not met, an exception will be thrown and no elements will be returned
    ///     even if some did meet the criteria
    /// </param>
    /// <returns>A list of all the web elements that match the condition specified</returns>
    public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds, int minNumberOfElements)
    {
        var wait = new DefaultWait<ISearchContext>(context);
        if (timeoutInSeconds > 0)
        {
            wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        }

        // Wait until the current context found the minimum number of elements. If not found after timeout, an exception is thrown
        wait.Until<bool>(ctx => ctx.FindElements(by).Count >= minNumberOfElements);

        //If the elements were successfuly found, just return the list
        return context.FindElements(by);
    }

}

使用例:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
// It can be now used to wait when using elements to search
var btn = main.FindElement(By.Id("button"),10);
btn.Click();
//This will wait up to 10 seconds until a button is found
var button = driver.FindElement(By.TagName("button"),10)
//This will wait up to 10 seconds until a button is found, and return all the buttons found
var buttonList = driver.FindElements(By.TagName("button"),10)
//This will wait for 10 seconds until we find at least 5 buttons
var buttonsMin= driver.FindElements(By.TagName("button"), 10, 5);
driver.Close();
0
havan

WebDriverWaitは有効になりません。

var driver = new FirefoxDriver(
    new FirefoxOptions().PageLoadStrategy = PageLoadStrategy.Eager
);
driver.Navigate().GoToUrl("xxx");
new WebDriverWait(driver, TimeSpan.FromSeconds(60))
    .Until(d => d.FindElement(By.Id("xxx"))); // a tag that close to the end

ページが「インタラクティブ」になるとすぐに例外が発生します。理由はわかりませんが、タイムアウトが存在しないように動作します。

おそらくSeleniumExtras.WaitHelpersは動作しますが、私は試しませんでした。それは公式ですが、他の小さなパッケージに分割されました。あなたは C#Selenium 'ExpectedConditionsは時代遅れです' を参照することができます。

私はFindElementsを使用していて、Count == 0がtrueであればawait Task.Delayを使用しているかどうかをチェックします。本当に効率的ではありません。

0
imba-tjd

これを達成することができます:

public static IWebElement WaitForObject(IWebDriver DriverObj, By by, int TimeOut = 30)
{
    try
    {
        WebDriverWait Wait1 = new WebDriverWait(DriverObj, TimeSpan.FromSeconds(TimeOut));
        var WaitS = Wait1.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.PresenceOfAllElementsLocatedBy(by));
        return WaitS[0];
    }
    catch (NoSuchElementException)
    {
        Reports.TestStep("Wait for Element(s) with xPath was failed in current context page.");
        throw;
    }
}
0
Krunal

This is the reusable function to wait for an element present in DOM using Explicit Wait. Public void WaitForElement(IWebElement element, int timeout = 2){ WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromMinutes(timeout)); wait.IgnoreExceptionTypes(typeof(NoSuchElementException)); wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException)); wait.Until<bool> (driver => { try { return element.Displayed; } catch(Exception) { return false; } }); }

0
Balakrishna