Selenium c # Webdriver: Tunggu Hingga Elemen Hadir

185

Saya ingin memastikan bahwa ada elemen sebelum webdriver mulai melakukan hal-hal.

Saya mencoba membuat sesuatu seperti ini berfungsi:

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

Saya terutama berjuang bagaimana mengatur fungsi anynomous ..

AyKarsi
sumber
3
FYI - lebih bersih untuk membangun rentang waktu Anda seperti ini TimeSpan.FromSeconds(5). Itu membuatnya lebih jelas IMO
Kolob Canyon

Jawaban:

159

Atau Anda dapat menggunakan tunggu implisit:

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

Penantian implisit adalah memberi tahu WebDriver untuk melakukan polling DOM selama waktu tertentu ketika mencoba menemukan elemen atau elemen jika tidak segera tersedia. Pengaturan default adalah 0. Setelah ditetapkan, tunggu implisit diatur selama masa instance objek WebDriver.

Mike Kwan
sumber
5
terima kasih, sintaks baru adalah: driver.manage (). timeout (). secara implisit Tunggu (10, TimeUnit.SECONDS);
Reda
20
@RedaBalkouch, sintaks yang digunakan Mike dalam Jawabannya benar. Ini C #
Diemo
3
Jika Anda memilih untuk menggunakan menunggu implisit, berhati-hatilah untuk tidak menggunakan tunggu eksplisit. Itu dapat menyebabkan beberapa perilaku yang tidak terduga yang mengarah pada hasil tes yang buruk. Secara umum, saya akan merekomendasikan menggunakan menunggu eksplisit daripada menunggu implisit.
mrfreester
7
Metode ini sekarang sudah tidak digunakan lagi, Anda sebaiknya menggunakan properti ImplicitWait:Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
Samuel Rondeau-Millaire
1
Saya menggunakan pendekatan yang disediakan dan menemukan metode itu sudah usang seperti yang ditunjukkan oleh Samuel. Memeriksa keberadaan item sekarang menunggu hingga waktu yang ditentukan.
Jim Scott
279

Menggunakan solusi yang disediakan oleh Mike Kwan dapat berdampak pada kinerja pengujian secara keseluruhan, karena menunggu implisit akan digunakan dalam semua panggilan FindElement. Sering kali Anda ingin FindElement gagal segera saat sebuah elemen tidak ada (Anda sedang menguji halaman yang salah bentuk, elemen yang hilang, dll.). Dengan menunggu implisit, operasi ini akan menunggu seluruh batas waktu berakhir sebelum melempar pengecualian. Default implisit wait diatur ke 0 detik.

Saya telah menulis sedikit metode ekstensi untuk ke IWebDriver yang menambahkan parameter batas waktu (dalam detik) ke FindElement()metode ini. Cukup jelas:

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

Saya tidak men-cache objek WebDriverWait karena pembuatannya sangat murah, ekstensi ini dapat digunakan secara bersamaan untuk objek WebDriver yang berbeda, dan saya hanya melakukan optimasi ketika akhirnya diperlukan.

Penggunaan mudah:

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();
Loudenvier
sumber
114
Dalam kasus seseorang bertanya-tanya, WebDriverWaitberasal dari OpenQA.Selenium.Support.UInamespace dan datang dalam paket terpisah meminta Selenium WebDriver Support ClassesNuGet
Andy
5
@ Ved aku bisa menciummu <3 telah mencarinya di dll yang berbeda: D
Adween
1
@Loudenvier Tolong buat baris pertama jadi lebih mencolok. Terutama karena itu bukan jawaban yang diterima, meskipun menjadi pendekatan yang lebih baik dan lebih tepat.
Rick
5
Selenium WebDriver Support Classessekarang muncul di NuGet sebagai "Selenium.Support" , versi saat ini adalah 3.4.0
Eric F.
1
Saya masih memiliki banyak kesalahan sampai saya menggunakan baris ini return wait.Until(ExpectedConditions.ElementToBeClickable(by));dan itu berfungsi dengan baik sekarang. Kepala jika-kalau ada orang lain mendapat elemen acak tidak ditemukan masih.
prospektor
84

Anda juga bisa menggunakan

ExpectedConditions.ElementExists

Jadi, Anda akan mencari ketersediaan elemen seperti itu

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

Sumber

Zain Ali
sumber
1
Setuju, ini jauh lebih berguna daripada batas waktu belaka (dalam kasus di mana Anda secara dinamis memuat objek).
keithl8041
5
Sementara ini berhasil. Sekarang ditandai sebagai usang, jadi harus dihindari.
Adam Garner
3
Inilah pendekatan baru (tidak usang): stackoverflow.com/a/49867605/331281
Dejan
1
Perhatikan bahwa, saat ini, DotNetSeleniumExtras.WaitHelpers(dirujuk oleh @Jejan di atas) "tidak dikelola, masalah tidak akan diperbaiki, PR tidak akan diterima". (sumber: github.com/SeleniumHQ/selenium/issues/… ). Penerbitnya sedang mencari pengelola untuk mengambil alih darinya.
urig
30

Berikut adalah variasi dari solusi @ Loudenvier yang juga berfungsi untuk mendapatkan beberapa elemen:

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);
    }
}
Rn222
sumber
7
Bagus! Saya baru saja menambahkan ini ke perpustakaan saya sendiri! Itulah keindahan kode berbagi !!!
Loudenvier
1
Saya sarankan satu tambahan untuk itu. Anda bisa menangkap solusi NoSuchElement dan mengembalikan null dalam contoh itu. Kemudian Anda bisa membuat metode ekstensi bernama .exists yang mengembalikan true kecuali IWebElement adalah nol.
Brantley Blanchard
17

Terinspirasi oleh solusi Loudenvier, berikut adalah metode ekstensi yang berfungsi untuk semua objek ISearchContext, bukan hanya IWebDriver, yang merupakan spesialisasi dari yang pertama. Metode ini juga mendukung menunggu hingga elemen ditampilkan.

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

Contoh penggunaan:

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();
aknuds1
sumber
1
Jika Anda telah menetapkan menunggu implisit seperti _webDriver.Manage().Timeouts().ImplicitlyWait(Timeout);itu masih akan mengalahkan nilai batas waktu yang Anda tetapkan di sini.
Howcheng
Ini sepertinya tidak berhasil untuk saya ...? Saya menambahkan Stopwatchsekitar panggilan ke metode ekstensi dan Console.WriteLine()di dalam lambda dikirim ke Until(). Stopwatch mengukur hampir tepat 60 detik dan hanya satu pesan yang ditulis Console. Apakah saya melewatkan sesuatu di sini?
urig
10

Saya Bingung fungsi apa pun dengan predikat. Inilah metode pembantu kecil:

   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)));
    }
AyKarsi
sumber
5

Anda dapat menemukan sesuatu seperti ini di C #.

Inilah yang saya gunakan di JUnit - Selenium

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

Apakah mengimpor paket terkait

Aditi
sumber
1
Saya berusaha untuk menggunakan ini hari ini dan VS.net memberi saya peringatan: kelas OpenQA.Selenium.Support.UI.ExpectedConditions telah ditandai "usang" dan "dimigrasikan ke repo DotNetSeleniumExtras" di 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"));
});
Brian121212
sumber
3
public bool doesWebElementExist(string linkexist)
{
     try
     {
        driver.FindElement(By.XPath(linkexist));
        return true;
     }
     catch (NoSuchElementException e)
     {
        return false;
     }
}
Madhu
sumber
Kode di atas adalah untuk memeriksa apakah elemen tertentu ada atau tidak.
Madhu
2

Perintah clickAndWait tidak dapat dikonversi ketika Anda memilih format Webdriver di Selenium IDE. Ini solusinya. Tambahkan garis tunggu di bawah ini. Secara realistis, masalahnya adalah klik atau peristiwa yang terjadi sebelum ini - baris 1 dalam kode C # saya. Tapi sungguh, pastikan Anda memiliki WaitForElement sebelum tindakan apa pun di mana Anda mereferensikan objek "oleh".

Kode HTML:

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

C # / NUnit kode:

driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();
MacGyver
sumber
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'))

dari EC Anda dapat memilih kondisi lain juga coba ini: http://selenium-python.readthedocs.org/api.html#module-selenium.webdriver.support.expected_conditions

Md. Nazmul Haque Sarker
sumber
Pertanyaan ini ditandai C #, bukan Python. Jawaban ini tidak relevan.
Pengguna
2

Coba kode ini:

 New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)
Ammar Ben Hadj Amor
sumber
4
Anda harus menjelaskan apa yang telah Anda lakukan dan mengapa ini menyelesaikan masalah. Dan tolong format kode Anda.
menggiring
1

Tunggu Eksplisit

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

Contoh:

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

Digunakan Rn222 dan Aknuds1 untuk menggunakan ISearchContext yang mengembalikan elemen tunggal, atau daftar. Dan jumlah minimum elemen dapat ditentukan:

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

}

Contoh penggunaan:

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();
havan
sumber
1

Anda tidak ingin menunggu terlalu lama sebelum elemen berubah. Dalam kode ini, driver web menunggu hingga 2 detik sebelum melanjutkan.

WebDriverWait wait = WebDriverWait baru (driver, TimeSpan.FromMilliseconds (2000));
wait.Until (ExpectedConditions.VisibilityOfAllElementsLocatedBy (By.Name ("html-name")));

pengguna3607478
sumber
1

Karena saya memisahkan definisi elemen halaman dan skenario pengujian halaman menggunakan IWebElement untuk visibilitas yang sudah ditemukan dapat dilakukan seperti ini:

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;
        }
    };
}
Angel_D
sumber
1

Ini adalah fungsi yang dapat digunakan kembali untuk menunggu elemen hadir dalam DOM menggunakan Tunggu Eksplisit.

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;
        }
    });
}
Balakrishna
sumber
Selamat datang di Stack Overflow, tolong jangan posting jawaban hanya kode.
JJ untuk Transparansi dan Monica
0

Kita bisa mencapai itu seperti ini:

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;
    }
}
Krunal
sumber
0

WebDriverWait tidak akan berpengaruh.

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

Ini akan langsung membuang pengecualian setelah halaman "interaktif". Saya tidak tahu mengapa tetapi batas waktu bertindak seolah-olah tidak ada.

Mungkin SeleniumExtras.WaitHelpersberhasil tetapi saya tidak mencoba. Ini resmi tetapi dibagi menjadi paket nuget lain. Anda dapat merujuk ke C # Selenium 'ExpectedConditions is obsolete' .

Saya sendiri menggunakan FindElementsdan memeriksa apakah Count == 0, jika benar, gunakan await Task.Delay. Benar-benar tidak efisien.

imba-tjd
sumber
0

Anda dapat menggunakan yang berikut ini

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

Saya melihat beberapa solusi yang sudah diposting yang berfungsi dengan baik! Namun, kalau-kalau ada yang membutuhkan sesuatu yang lain, saya pikir saya akan memposting dua solusi yang saya pribadi gunakan dalam selenium C # untuk menguji apakah ada elemen! Semoga ini bisa membantu, tepuk tangan!

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

}

Ini yang kedua

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

}
newITguy
sumber
-1
 new WebDriverWait(driver, TimeSpan.FromSeconds(10)).
   Until(ExpectedConditions.PresenceOfAllElementsLocatedBy((By.Id("toast-container"))));
David
sumber
Kondisi yang
-1

Jawaban pertama adalah baik, masalah saya adalah pengecualian yang tidak tertangani tidak menutup driver web dengan benar dan itu menjaga nilai pertama yang sama yang saya gunakan yaitu 1 detik.

Jika Anda mendapatkan masalah yang sama

restart you visual studiodan memastikan itu all the exceptions are handleddengan benar.

Pete Kozak
sumber
Sekarang Anda harus tahu bahwa tidak ada pemesanan untuk jawaban di Stack Overflow, jadi tidak ada "jawaban pertama"
Antti Haapala
-2

Sedang mencari cara menunggu di Selenium untuk kondisinya, mendarat di utas ini dan inilah yang saya gunakan sekarang:

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

ReadCell(row, col) != ""dapat kondisi apa pun. Suka seperti ini karena:

  • ini milikku
  • memungkinkan inlining
Mars Robertson
sumber