簡體   English   中英

如何讓 webDriver 等待頁面加載(C# Selenium 項目)

[英]How to get webDriver to wait for page to load (C# Selenium project)

我已經在 C# 中啟動了一個 Selenium 項目。 嘗試等待頁面完成加載,然后才進行下一步操作。

我的代碼如下所示:

 loginPage.GoToLoginPage();
        loginPage.LoginAs(TestCase.Username, TestCase.Password);
        loginPage.SelectRole(TestCase.Orgunit);
        loginPage.AcceptRole();

在 loginPage.SelectRole(TestCase.Orgunit) 中:

 RoleHierachyLabel = CommonsBasePage.Driver.FindElement(By.XPath("//span[contains(text(), " + role + ")]"));
 RoleHierachyLabel.Click();
 RoleLoginButton.Click();

我搜索元素 RoleHierachyLabel。 我一直在嘗試使用多種方法來等待頁面加載或搜索允許一些超時的元素屬性:

1. _browserInstance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));

2. public static bool WaitUntilElementIsPresent(RemoteWebDriver driver, By by, int timeout = 5)
    {
        for (var i = 0; i < timeout; i++)
        {
            if (driver.ElementExists(by)) return true;
        }
        return false;
    }

你會如何解決這個障礙?

我一直在尋找替代方案,並確定了以下版本。 所有都使用具有定義超時的顯式等待,並且在第一種情況下基於元素屬性,在第二種情況下基於元素陳舊性。

第一選擇是檢查元素屬性,直到達到超時。 我已經到達以下屬性,確認它在頁面上可用:

存在- 檢查元素是否存在於頁面的 DOM 上的期望。 這並不一定意味着該元素是可見的。

//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Enabled)

//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementExists(By elementLocator, int timeout = 10)
    {
        try
        {
            var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
            return wait.Until(ExpectedConditions.ElementExists(elementLocator));
        }
        catch (NoSuchElementException)
        {
            Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
            throw;
        }
    }

可見性- 檢查元素是否存在於頁面的 DOM 上並且可見的期望。 可見性意味着元素不僅被顯示,而且其高度和寬度都大於 0。

//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Displayed)

//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementVisible(By elementLocator, int timeout = 10)
    {
        try
        {
            var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
            return wait.Until(ExpectedConditions.ElementIsVisible(elementLocator));
        }
        catch (NoSuchElementException)
        {
            Console.WriteLine("Element with locator: '" + elementLocator + "' was not found.");
            throw;
        }
    }

Clickable - 檢查元素是否可見並啟用的期望,以便您可以單擊它。

//this will not wait for page to load
//both properties need to be true in order for element to be clickable
Assert.True(Driver.FindElement(By elementLocator).Enabled)
Assert.True(Driver.FindElement(By elementLocator).Displayed)

//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementClickable(By elementLocator, int timeout = 10)
    {
        try
        {
            var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
            return wait.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
        }
        catch (NoSuchElementException)
        {
            Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
            throw;
        }
    }

當觸發器對象(例如菜單項)在單擊后不再附加到 DOM 時,第二個選擇適用。 這通常是在元素上的單擊操作將觸發重定向到另一個頁面時的情況。 在這種情況下,檢查 StalenessOf(element)很有用,其中 element 是被單擊以觸發重定向到新頁面的項目。

public static void ClickAndWaitForPageToLoad(By elementLocator, int timeout = 10)
    {
        try
        {
            var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
            var element = Driver.FindElement(elementLocator);
            element.Click();
            wait.Until(ExpectedConditions.StalenessOf(element));
        }
        catch (NoSuchElementException)
        {
            Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
            throw;
        }
    }

driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);

另外,請參閱此答案

我通常對此使用顯式等待,並等待元素可見,然后進行下一個操作。 這應該是這樣的:

WebDriverWait waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
waitForElement.Until(ExpectedConditions.ElementIsVisible(By.Id("yourIDHere")));

更多關於顯式等待的信息: 顯式等待 Selenium C#和這里WebDriver 顯式等待

剛剛有同樣的問題。 使用以下方法,我等待頁面完全加載,而不依賴於通過 JavaScript、單擊或輸入元素上的操作導致頁面加載。

private void WaitForPageToLoad(Action doing)
{
    IWebElement oldPage = _driver.FindElement(By.TagName("html"));
    doing();
    WebDriverWait wait = new WebDriverWait(_driver, new TimeSpan(0, 0, Timeout));
    try
    {
        wait.Until(driver => ExpectedConditions.StalenessOf(oldPage)(_driver) &&
            ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
    }
    catch (Exception pageLoadWaitError)
    {
        throw new TimeoutException("Timeout during page load", pageLoadWaitError);
    }
}

調用如下

WaitForPageToLoad(() => _driver.FindElement(By.Id("button1")).Click());

我這樣做是為了解決此類問題。 它是計時器和循環的組合,它們正在尋找特定元素,直到它在特定毫秒數后超時。

private IWebElement FindElementById(string id, int timeout = 1000)
{
    IWebElement element = null;

    var s = new Stopwatch();
    s.Start();

    while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
    {
        try
        {
            element = _driver.FindElementById(id);
            break;
        }
        catch (NoSuchElementException)
        {
        }
    }

    s.Stop();
    return element;
}

我還為啟用元素做了一個

private IWebElement ElementEnabled(IWebElement element, int timeout = 1000)
{
    var s = new Stopwatch();
    s.Start();

    while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
    {
        if (element.Enabled)
        {
            return element;
        }
    }

    s.Stop();
    return null;
}

在 Selenium等待頁面加載中所述:

通常,在 Selenium 2.0 中,Web 驅動程序應僅在確定頁面已加載后將控制權返回給調用代碼 如果沒有,您可以調用waitforelemement ,它會循環調用findelement直到找到它或超時(可以設置超時)。

由於它的簡單性,我喜歡這個解決方案。 它還具有避免過度等待和排除可能是等待上限的猜測工作的好處:

    public bool WaitToLoad(By by)
    {
        int i = 0;
        while (i < 600)
        {
            i++;
            Thread.Sleep(100); // sleep 100 ms
            try
            {
                driver.FindElement(by);
                break;
            }
            catch { }
        }
        if (i == 600) return false; // page load failed in 1 min
        else return true;
    }

如果需要監控頁面加載延遲,可以修改它以還包括一個“計時器”:

    public int WaitToLoad(By by)
    {
        int i = 0;
        while (i < 600)
        {
            i++;
            Thread.Sleep(100); // sleep 100 ms
            try
            {
                driver.FindElement(by);
                break;
            }
            catch { }
        }
        return i; // page load latency in 1/10 secs
    }

你只需要通過 NuGet 導入 SeleniumExtras 包,然后像下面這樣使用它:

var e = new WebDriverWait(driver, new TimeSpan(0, 0, 60)).Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.Id("--id")));

這里的所有回答都沒有任何意義。 頁面可以包含所有控件。 但是你改變了一些東西,控件中的數據發生了變化,頁面進入了重新加載狀態。 所以如果你繼續使用這個頁面,你會得到一堆錯誤。 真的,我沒有看到比 Thread.Sleep() 更好的解決方案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM