Selenyum c # Webdriver: Öğe Var Olana Kadar Bekleyin


185

Web sürücüsü bir şeyler yapmaya başlamadan önce bir öğenin bulunduğundan emin olmak istiyorum.

Çalışmak için böyle bir şey elde etmeye çalışıyorum:

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

Ben esas olarak, anonom fonksiyonun nasıl kurulacağına uğraşıyorum.


3
FYI - zaman diliminizi bu şekilde oluşturmak daha temiz TimeSpan.FromSeconds(5). Bu daha açık hale getirir IMO
Kolob Canyon

Yanıtlar:


159

Alternatif olarak örtülü bekleme özelliğini kullanabilirsiniz:

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

Örtük bir bekleme, WebDriver'a bir öğeyi veya öğeleri hemen bulunmuyorsa bulmaya çalışırken DOM'u belirli bir süre boyunca yoklamasını söylemektir. Varsayılan ayar 0'dır. Belirlendiğinde, örtülü bekleme WebDriver nesnesi örneğinin ömrü boyunca ayarlanır.


5
teşekkürler, yeni sözdizimi şöyledir: driver.manage (). timeouts (). implicitlyWait (10, TimeUnit.SECONDS);
Reda

20
@RedaBalkouch, Mike'ın Yanıtında kullandığı sözdizimi doğrudur. It's C #
Diemo

3
Örtülü beklemeler kullanmayı seçerseniz, kesin beklemeler kullanmamaya dikkat edin. Bu, kötü test sonuçlarına yol açan bazı öngörülemeyen davranışlara neden olabilir. Genel olarak, örtük beklemeler üzerinde açık beklemeler kullanmanızı tavsiye ederim.
mrfreester

7
Bu yöntem artık kullanımdan kaldırılmıştır, bunun yerine ImplicitWait özelliğini kullanmalısınız:Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
Samuel Rondeau-Millaire 31:17

1
Verilen yaklaşımı kullandım ve Samuel'in işaret ettiği yöntemin kullanımdan kaldırıldığını gördüm. Bir öğenin varlığını kontrol etmek artık belirtilen süreyi bekliyor.
Jim Scott

279

Örtülü bekleme tüm FindElement çağrılarında kullanılacağından, Mike Kwan tarafından sağlanan çözümün kullanılması genel test performansında etkili olabilir. Çoğu zaman, bir öğe mevcut olmadığında FindElement öğesinin hemen başarısız olmasını istersiniz (hatalı biçimlendirilmiş bir sayfayı, eksik öğeleri vb. Test ediyorsunuz). Örtülü bekleme ile bu işlemler istisnayı atmadan önce tüm zaman aşımı süresinin dolmasını bekler. Varsayılan örtülü bekleme 0 saniyeye ayarlanmıştır.

Yönteme bir zaman aşımı (saniye cinsinden) parametresi ekleyen IWebDriver'a küçük bir uzantı yöntemi yazdım FindElement(). Oldukça açıklayıcı:

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

Oluşturulması çok ucuz olduğu için WebDriverWait nesnesini önbelleğe almadım, bu uzantı farklı WebDriver nesneleri için aynı anda kullanılabilir ve yalnızca nihayetinde gerektiğinde optimizasyon yaparım.

Kullanımı basittir:

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

114
Birisi merak ederse WebDriverWait, OpenQA.Selenium.Support.UIad alanından ve Selenium WebDriver Support ClassesNuGet
Andy

5
@Ved seni öpebilirim <3 farklı bir dll içinde aradılar: D
Adween

1
@Loudenvier Lütfen daha dikkat çekici olması için ilk satırı kalın yapın. Özellikle daha iyi ve daha kesin bir yaklaşım olmasına rağmen kabul edilen cevap olmadığı için.
Rick

5
Selenium WebDriver Support Classesşimdi NuGet'te "Selenium.Support" olarak yayınlandı , şu anki sürüm 3.4.0
Eric

1
Bu satırı kullanana kadar hala birçok hatam vardı return wait.Until(ExpectedConditions.ElementToBeClickable(by));ve şimdi harika çalışıyor. Başka birisinin hala bulunmayan rastgele elemanlar alması durumunda dikkat edin.
müstakbel

84

Ayrıca kullanabilirsiniz

ExpectedConditions.ElementExists

Böylece, böyle bir öğenin kullanılabilirliğini arayacaksınız

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

Kaynak


1
Kabul edildiğinde, bu yalnızca bir zaman aşımından çok daha kullanışlıdır (bir nesneyi dinamik olarak yüklediğiniz durumlarda).
keithl8041

5
Bu çalışırken. Artık kullanımdan kaldırılmış olarak işaretlendiğinden kaçınılmalıdır.
Adam Garner

3
İşte yeni yaklaşım (kullanımdan kaldırılmamış): stackoverflow.com/a/49867605/331281
Dejan

1
Şu anda, DotNetSeleniumExtras.WaitHelpers(yukarıdaki @Dejan tarafından değinilmiştir) "korunmaz, sorunların düzeltilmeyeceğini, PR'ların kabul edilmeyeceğini" unutmayın. (kaynak: github.com/SeleniumHQ/selenium/issues/… ). Yayıncısı, onu kendisinden devralmak için bir koruyucu arıyor.
urig

30

Birden fazla öğe almak için çalışan @ Loudenvier'nin çözümünün bir çeşidi:

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

7
Güzel! Bunu kendi kütüphaneme ekledim! Bu kod paylaşmanın güzelliği !!!
Loudenvier

1
Buna bir ţey önerebilirim. NoSuchElement çözümünü yakalayabilir ve bu örnekte null değerini döndürebilirsiniz. Sonra IWebElement boş değilse true döndüren .exists adlı bir uzantı yöntemi oluşturabilirsiniz.
Brantley Blanchard

17

Loudenvier'nin çözümünden esinlenerek, burada sadece birincisinin uzmanlığı olan IWebDriver için değil, tüm ISearchContext nesneleri için çalışan bir uzantı yöntemi. Bu yöntem, öğe görüntülenene kadar beklemeyi de destekler.

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

Örnek kullanım:

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

1
Bunun gibi örtük bir bekleme _webDriver.Manage().Timeouts().ImplicitlyWait(Timeout);ayarladıysanız, burada ayarladığınız zaman aşımı değerini bozmaya devam eder.
howcheng

Bu benim için işe yaramıyor ...? StopwatchUzatma yöntemine bir çağrı ekledim ve Console.WriteLine()gönderilen lambda'nın içine bir tane ekledim Until(). Kronometre neredeyse tam 60 saniye ölçüldü ve sadece bir mesaj yazıldı Console. Burada bir şey mi eksik?
urig

10

Ben anomoz fonksiyonu yüklemle karıştırdım. Heres küçük bir yardımcı yöntem:

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

5

C # 'da böyle bir şey bulabilirsiniz.

JUnit - Selenium'da kullandığım şey bu

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

İlgili paketleri içe aktarma


1
Bunu bugün kullanmaya çalıştım ve VS.net bana uyarı veriyor: OpenQA.Selenium.Support.UI.ExpectedConditions sınıfı "kullanımdan kaldırıldı" olarak işaretlendi ve " github.com/DotNetSeleniumTools
Jeff Mergler

3
//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"));
});

3
public bool doesWebElementExist(string linkexist)
{
     try
     {
        driver.FindElement(By.XPath(linkexist));
        return true;
     }
     catch (NoSuchElementException e)
     {
        return false;
     }
}

Yukarıdaki kod, belirli bir elemanın mevcut olup olmadığını kontrol etmektir.
Madhu

2

Selenium IDE'de Web sürücüsü biçimini seçtiğinizde clickAndWait komutu dönüştürülmez. İşte geçici çözüm. Aşağıdaki bekleme satırını ekleyin. Gerçekçi olarak, sorun C # kodumda bu bir satır 1'den önce gerçekleşen tıklama veya olaydı. Ama gerçekten, bir "By" nesnesine başvurduğunuz herhangi bir eylemden önce bir WaitForElement öğeniz olduğundan emin olun.

HTML Kodu:

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

C # / N Birim kodu:

driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();

2

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'den başka koşulları da seçebilir ve şunu deneyebilirsiniz: http://selenium-python.readthedocs.org/api.html#module-selenium.webdriver.support.expected_conditions


Bu soru Python değil C # olarak etiketlenmiştir. Bu cevap ilgisiz.
Kullanıcı

2

Bu kodu deneyin:

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

4
Ne yaptığınızı ve bunun neden sorunu çözdüğünü açıklamalısınız. Ve lütfen kodunuzu biçimlendirin.
hering

1

Açık Bekleyin

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

Misal:

wait.until(ExpectedConditions.visibilityOfElementLocated(UiprofileCre.UiaddChangeUserLink));

1

Tek bir öğe veya bir liste döndüren bir ISearchContext kullanmak için Rn222 ve Aknuds1 kullanılır. Ve minimum sayıda eleman belirtilebilir:

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

}

Örnek kullanım:

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

1

Öğe değişmeden çok fazla beklemek istemezsiniz. Bu kodda web sürücüsü devam etmeden önce 2 saniye bekler.

WebDriverWait wait = yeni WebDriverWait (sürücü, TimeSpan.FromMilliseconds (2000));
wait.Until (ExpectedConditions.VisibilityOfAllElementsLocatedBy (By.Name ( "html adı")));


1

Görünürlük için zaten bulunan IWebElement'i kullanarak sayfa öğeleri tanımlarını ve sayfa testi senaryolarını ayırdığım için şu şekilde yapılabilir:

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

Bu, Açık Bekleme'yi kullanarak DOM'da bulunan bir öğeyi beklemek için yeniden kullanılabilir işlevdir.

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

Stack Overflow'a hoş geldiniz, lütfen sadece kod cevapları göndermeyin.
JJ for Transparency ve Monica

0

Bunu şu şekilde başarabiliriz:

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

WebDriverWait etkili olmayacak.

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

Sayfa "etkileşimli" olduğunda bu derhal bir istisna oluşturur. Nedenini bilmiyorum ama zaman aşımı yokmuş gibi davranıyor.

Belki SeleniumExtras.WaitHelpersişe yarıyor ama denemedim. Resmi ama başka bir nuget paketine bölündü. C # Selenium 'ExpectedConditions is old' ifadesine başvurabilirsiniz .

Kendim kullanıyor FindElementsve Count == 0eğer doğruysa kullanılıp kullanılmadığını kontrol ediyor await Task.Delay. Gerçekten çok verimli değil.


0

Aşağıdakileri kullanabilirsiniz

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

-1

Zaten işe yarayan çok sayıda çözümün harika çalıştığını görüyorum! Ancak, herkesin başka bir şeye ihtiyacı olması durumunda, bir elementin mevcut olup olmadığını test etmek için kişisel olarak selenyum C #'da kullandığım iki çözüm yayınlayacağımı düşündüm! Umarım yardımcı olur, şerefe!

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; 
    }

}

İşte ikinci

    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; 
    }

}

-1
 new WebDriverWait(driver, TimeSpan.FromSeconds(10)).
   Until(ExpectedConditions.PresenceOfAllElementsLocatedBy((By.Id("toast-container"))));

ExpectedConditions kullanımdan kaldırıldı
GELR

-1

İlk cevap iyidir, sorunum işlenmeyen istisnalar web sürücüsünü düzgün bir şekilde kapatmadı ve 1 saniye olan aynı ilk değeri tuttu.

Aynı sorunu alırsanız

restart you visual studiove all the exceptions are handleduygun şekilde olmasını sağlayın .


Şimdiye kadar Stack Overflow cevaplar için bir sipariş olduğunu bilmelisiniz, bu yüzden "ilk cevap" yoktur
Antti Haapala

-2

Durum için Selenium beklemek için arama, bu iş parçacığında indi ve işte şimdi ne kullanıyorum:

    WebDriverWait wait = new WebDriverWait(m_driver, TimeSpan.FromSeconds(10));
    wait.Until(d => ReadCell(row, col) != "");

ReadCell(row, col) != ""herhangi bir koşul olabilir. Bu şekilde olduğu için:

  • bu benim
  • satır içine izin verir
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.