Ошибка при добавлении ожидания загрузки страницы.

Добрый день.
Есть тесты на C#+Selenium WebDriver
Раньше в тестах у меня везде, где надо ждать загрузки стоят Thread.sleep(1000);
Потом я решил, что это не очень кошерно и сделал метод

public void WaitForLoad()
{
    Manage().Timeouts().SetPageLoadTimeout(new TimeSpan(0,0,60));
}

После чего тесты начали падать с ошибкой:

Test(s) failed. OpenQA.Selenium.ElementNotVisibleException : Cannot click on element
   at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse)
   at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Remote.RemoteWebElement.Click()
   at driver.GeniusFirefoxDriver.Click(IWebElement element) in c:\TestNew\Driver\GeniusFirefoxDriver.cs:line 140
   at NKBSTests.Pages.ROAgentPage.OpenCertainDocMenu(String group, String type) in c:\TestNew\NKBSTests\Pages\ROAgent\ROAgentPage.cs:line 56
   at NKBSTests.Tests.Docs.CreateDocTests.AAPublishDocAndCheckInMenuROAgent() in c:\TestNew\NKBSTests\Tests\Docs\CreateDocTests.cs:line 329

Вот метод, который валит ошибку:

public static void OpenCertainDocMenu(string group, string type)
{
    Actions actions = new Actions(Browser);
    Browser.WaitForLoad();
    actions.MoveToElement(Browser.FindElement(By.XPath(XpathForMenuInAgent + group + "']"))).Perform();
    Browser.Click(Browser.FindElement(By.XPath(XpathForMenuInAgent + type + "']")));
}

Т.е. по задумке надо дождаться загрузки страницы, потом навести на пункт меню и кликнуть по подпункту в выпадающем списке.
56 строка - это последняя в этом методе. Если навтыкать Thread.sleep’ов, то всё работает, т.е. элементы присутствуют, просто не успевают прогрузиться.
Добавил ещё в метод Click(); такую шляпу:

public void Click(IWebElement element)
        {
            WaitForAjax();
            element.Click();
            WaitForLoad();
            WaitForAjax();
        }

Но тест всё равно падает с той же ошибкой.
Подскажите, в чём я неправ и как это грамотно сделать?

WebDriver будет считать страницу загруженной, когда на самой страница сработает событие document.ready(), а это событие срабатывает когда все статические файлы и файлы javascript уже загруженны, но еще не выполнялись.

Для JavaScript внутри страницы, document.ready() – это лишь сигнал для того, чтобы начать работу, поэтому, если у вас UI строится через JavaScript и ajax запросы, то WebDriver будет считать страницу загруженной до их полного выполнения.

Решить проблемму можно так:

Короткий ответ, вам нужно дождатся элемента прежде чем производить с ним действия

2 лайка

Этот метод действует не как sleep, а как установка параметра для ожидания загрузки страницы. То есть вызывать его каждый раз перед ожиданием элемента (как sleep) - бессмысленно

Ну и методы решения Дмитрий @dzhariy подсказал

1 лайк

Спасибо. Сделал явное ожидание, но пока не понял, работает или нет.
Нарисовалась такая проблема:

Практически в начале теста я щёлкаю по элементу и после этого надо выбрать один пункт из выпадающего меню, но сделать это надо на следующей странице после того, как она прогрузится, а элемент присутствует и на этой странице тоже.
Подскажите, как кроме Thread.sleep() дать понять вёбдрайверу, что элемент надо искать не на этой странице, а подождать следующую. Сейчас получается, что тест находит элемент, пытается по нему кликнуть, но страница перезагружается и тест падает.

Один из вариантов дождаться загрузки страницы, это

  1. выбрать уникальный элемент на странице, которую мы ждем
  2. Ждать пока он не появится
1 лайк

Помимо ожидания появления элемента, можно ожидать и его “исчезновения” - StaleElementReferenceException

1 лайк

Сейчас проблема в том, что тест иногда проходит нормально, а иногда падает с такой ошибкой:

Test(s) failed. OpenQA.Selenium.InvalidSelectorException : The xpath expression '//*[contains(@id, 'agentMenu') and text()='Передача данных']' cannot be evaluated or does notresult in a WebElement
   at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse)
   at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(String mechanism, String value)
   at OpenQA.Selenium.Remote.RemoteWebDriver.FindElementByXPath(String xpath)
   at OpenQA.Selenium.By.<>c__DisplayClasse.<XPath>b__c(ISearchContext context)
   at OpenQA.Selenium.By.FindElement(ISearchContext context)
   at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(By by)
   at NKBSTests.Pages.ROAgentPage.OpenCertainDocMenu(String group, String type) in c:\TestNew\NKBSTests\Pages\ROAgent\ROAgentPage.cs:line 56
   at NKBSTests.Tests.Docs.CreateDocTests.AAPublishDocAndCheckInMenuROAgent() in c:\TestNew\NKBSTests\Tests\Docs\CreateDocTests.cs:line 331

Падает вот на этом моменте:

public static void OpenCertainDocMenu(string group, string type)
{
    //var actions = new Actions(Browser);
    //actions.MoveToElement(Browser.FindElement(By.XPath(XpathForMenuInAgent + group + "']"))).Perform();
    Browser.iClick(Browser.FindElement(By.XPath(XpathForMenuInAgent + group + "']")));
    Browser.iClick(Browser.FindElement(By.XPath(XpathForMenuInAgent + type + "']"))); // строка 56
}

Т.е. сначала выбирается пункт меню, а потом подпункт.
(Я именно кликаею по пункту, а не выбираю через наведение, как надо, по идее, потому что с наведением в IE были какие-то проблемы, сейчас уже не помню, у строки с наведением закомментированы )
Проблема в том, как я понял, что WebDriver после того, как кликает по разделу меню иногда успевает найти элемент подраздела до загрузки страницы и тогда вываливается исключение, а иногда нет, и тогда отрабатывает нормально. Проблема в том, что это одна и та же страница и никаких уникальных элементов на ней нет. Насколько кошерно делать так

Browser.iClick(Browser.FindElement(By.XPath(XpathForMenuInAgent + group + "']")));
Thread.sleep(1000);
Browser.iClick(Browser.FindElement(By.XPath(XpathForMenuInAgent + type + "']"))); // строка 56

Это будет работать, но, может, есть какой-нибудь более правильный вариант?

Создавайте WebDriverWait и игнорьте этот эксепшен, желательно на глобальном уровне, поскольку данное исключение довольно неприятная штука в IE.
Как вариант обновите драйвер - может поможет :slight_smile:

Проигнорить-то я, конечно, могу, но какой в этом смысл, если он всё равно не находит элемент?

Не понял. Речь о WebDriverWait.IgnoreExceptionTypes

Не, я имел ввиду “проигнорить” с помощью catch(Exception e)