Как заставить webDriver ждать загрузки страницы (проект Selenium С#)

Я начал проект 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;
    }

Как бы вы справились с этим препятствием?

Ответ 1

Я искал альтернативы, и я решил использовать следующие версии. Все используют явное ожидание с заданным таймаутом и основаны на свойствах элемента в первом случае и на стойкости элемента во втором случае.

Первый выбор будет проверять свойства элемента до тех пор, пока не будет достигнут тайм-аут. Я пришел к следующим свойствам, подтверждающим, что он доступен на странице:

Существование. Ожидание проверки того, что элемент присутствует в 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 после его нажатия. Это обычно происходит, когда действие click на элементе вызывает перенаправление на другую страницу. В этом случае полезно проверить StalenessOf (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;
        }
    }

Ответ 2

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

Также см. этот ответ

Ответ 3

Я обычно использую явное ожидание этого и жду, пока элементы будут видны, а затем перейдите к следующему действию. Это должно выглядеть так:

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

Подробнее о явном ожидании здесь: Явно ждет Selenium С# и здесь WebDriver Explicit ждет

Ответ 4

Я сделал это для решения этой проблемы. Это комбинация таймеров и циклов, которые ищут определенный элемент, пока он не истечет через определенное количество миллисекунд.

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

Ответ 5

Как сказано в " Ожидание загрузки страницы в Selenium":

В целом, в Selenium 2.0 веб-драйвер должен возвращать управление вызывающему коду только после того, как определит, что страница загружена. Если это не так, вы можете вызвать waitforelemement, который циклически findelement вызов findelement до findelement пор, пока он не будет найден или не findelement время ожидания (можно установить время ожидания).

Ответ 6

Из-за своей простоты мне нравится это решение. Кроме того, у него есть преимущество, заключающееся в том, что он избегает чрезмерных ожиданий и устраняет необходимость в предположении того, что может быть верхним пределом ожидания:

    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
    }