Как заставить webDriver ждать загрузки страницы (проект C# Selenium)
Я начал проект Селена в C#. Попытка дождаться завершения загрузки страницы и только после этого перейти к следующему действию.
мой код выглядит так:
 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;
    }
как вы бы справились с этим препятствием?
4 ответов
Я искал альтернативы и я остановился на следующих вариантах. Все они используют явное ожидание с определенным таймаутом и основаны на свойствах элемента в первом случае и на стойкости элемента во втором случае.
выбор будет проверять свойства элемента до тех пор, пока не будет достигнут тайм-аут. Я прибыл к следующим свойствам, которые подтверждают, что он доступен на странице:
существование - ожидание для проверка наличия элемента в 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 (элемент) где элемент-элемент, который был нажат для запуска перенаправления на новую страницу.
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 явно ждет
Я сделал это, чтобы решить эту проблему. Это комбинация таймеров и циклов, которые ищут определенный элемент, пока он не выйдет через определенное количество миллисекунд.
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;
}