Wait не работает, элемент не находит, подскажите плз решение

Здравствуйте!
На Log in page есть 1 текстовое поле, для эл.адреса. Есть класс, в котором существует 3 warning message. Для каждого кейса своя ошибка выдается.
Я сделала так: написала функцию , которая находит класс, и все warning кидает в массив.
Затем написала функцию, которая ожидает появления этой ошибки.
И у меня вылетает на wait

Код C#

 //Get WarningMessage
        public string ErrorMessage(string email, int i)
        {
            FillForm(email);           
            if (IsDisplayed(_errorMsg, 1))
            {
                return GetErrorMessage(_errorMsg, i);
            }
            else
            {
                return null;
            }

        }

  //Check if element is available
        protected bool IsDisplayed(By locator, int avgWaitTime)
        {
            try
            {
                WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMinutes(avgWaitTime));
                wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(locator));
                return true;
            }
            catch (WebDriverTimeoutException)
            {
                Console.WriteLine("Damn");
                return false;
            }

        }

Логи и ошибка вот такая

Expected: null
  But was:  "This email address is not registered. Please contact your hiring manager."

FireFox 62.0
geckodriver v0.20

Ну, во-первых, WebDriverWait нужно вынести на уровень instance переменной. У вас на каждый чих создаются новые объекты, что не имеет никакого смысла.

Во-вторых, вы разбили одну простую операцию на 2: вызов isDisplayed и GetErrorMessage (который еще не понятно, как реализован).

VisibilityOfAllElementsLocatedBy уже итак возвращает вам список элементов. Но вы благополучно игнорируете результат Until, возвращая true / false.

Ошибка скорее всего летит на assertion операции (которую вы тоже упустили, надеясь на экстрасенсорные способности комьюнити).

Покажите весь фрагмент кода. Но для начала, его желательно упростить в соответствии с выше указанными замечаниями.

Спасибо за ответ.
Вот сам тест кейс:

 [Description("Test case for not valid email")]
        [Test]
        public void NotValidEmail()
        {
            NavToLogin NavToLogin = new NavToLogin(driver);
            string actual_Result = NavToLogin.ErrorMessage(NavToLogin_Const.invalidEmail, 1);
            string expected_Result = NavToLogin_Const.notValidEmailMsg;
            Assert.AreEqual(actual_Result, expected_Result);
        }
 //Get WarningMessage
        public string ErrorMessage(string email, int i)
        {
            FillForm(email);
            return IsDisplayed(_errorMsg, 1, i);
        }
    public string IsDisplayed(By locator, int avgWaitTime, int i)
        {
            try
            {
                wait = new WebDriverWait(driver, TimeSpan.FromMinutes(avgWaitTime));
                //find all error messages using visibilityOfAllElementsLocatedBy
                Thread.Sleep(10000);
                IList<IWebElement> errorMessages = 
 wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(locator));
                //get the number of messages found 
                int msgCount = errorMessages.Count;
                Assert.Equals(msgCount, 3);
                return errorMessages[i].Text;
            }
            catch (WebDriverTimeoutException)
            {

                return "Damn";
            }

        }

Может я локатор не правильно подобрала… все равно на wait вылетает.

Я новичок в автоматизации, простите, если где-то туплю.

Для простоты поддержки Вашего кода я бы изменил немного логику:

  1. У метод называется ErrorMessage(string email, int i), я бы переназвал его GetWarningMessage, тут не понятно что такое “i” - какойто индэкс ошибки? думаю от него лучше избавится
  2. метод возвращает текст ошибки, но внутри самого метода идет визов метода " FillForm(email);", зачем?
    предлагаю Вам вынести логику теста в сам тест:
    public void NotValidEmail()
    {
    NavToLogin NavToLogin = new NavToLogin(driver);
    go to some page
    FillForm(email);
    Assert.AreEqual(NavToLogin.getErrorMessage(), NavToLogin_Const.notValidEmailMsg);
    }
  3. по поводу метода “IsDisplayed”, когда метод начинается со слова “is” то предполагается, что он булеан, у Вас один раз так а вдругом варианте уже типа string… думаю булеан самое подходящее
  4. не хорошо возвращать “null” в методе, если Вы этот “null” не обрабатываете потом, лучше всего в данной ситуации вернуть просто пустую строку
  5. все таки нужен короткий HTML и xpath локатор, который Вы используете чтобы понять почему именно не работает метод
1 лайк

Коротко о наболевшем:

  1. Thread.Sleep(10000); - убрать. И вообще забыть о таких вещах.
  2. Методы с именем типа IsDisplayed должны возвращать true/false, а не string.
    У вас название метода как бы говорит “Отображен ли такой-то элемент?”
    А в ответ приходит какая-то стринга…

По ошибке:

Более чем уверен, что проблема кроется вот тут:

Assert.AreEqual(actual_Result, expected_Result);

Данный метод принимает первым аргументом - Expected, а не Actual.
Вторым - Actual, а не Expected.
У вас они перепутаны местами.

Отсюда вытекает следующее, что на самом деле ошибка говорит вам:

Expected: "This email address is not registered. Please contact your hiring manager."
  But was:  null

У вас возвращается null.

Полагаю, что скорее всего null возвращается вот здесь: return errorMessages[i].Text;
Вы передаёте как индекс переменную i, которая у вас равняется 1.
Индекс в коллекции начинается с 0. Для получения текста первой ошибки нужно исправить это место на:
return errorMessages[i - 1].Text;
После этого ошибка у вас должна быть правильной, если нет других проблем.

PS: Используйте лучше Assert.That в купе с Is/Has/Or/Not и тд.

Да и вообще, у вас много где можно код написать более правильно.
Например - передавать в метод TimeSpan, а не int.
И, конечно же, не использовать Assert внутри методов.

2 лайка

Спасибо, ссейчас переделаю, индекс 1, ибо, под 0ым индексом, другая ошибка, там в классе 3 сообщения , каждая всплывает в соответствии с тем , что вводится в текстовое поле.

У вас в коллекции 3 ошибки.
Индексы этих ошибок будут следующие: 0, 1, 2.

Если вы хотите получить текст первой ошибки - нужно использовать индекс 0.

Нет, в данном методе мне нужна 2ая ошибка, дело в том, что первую я всегда получаю правильно… :confused:

Можете показать под дебагом, что возвращается в коллекции элементов? Включая их свойства.
Полагаю, в таком случае ошибка либо в локаторах, либо текст самой ошибки отсутствует.

Ничего не возвращает,

сразу вылетел…

Ну, не сразу. Он прождал минуту, которую вы передали в объект WebDriverWait.

Здесь проблема кроется в одном из пунктов, проверяйте по порядку:

  1. Убедитесь в правильности написания локатора. Проверьте его в браузере руками, что он находит коллекцию объектов.
    Если локатор написан с ошибками - то, соответственно, вы никогда не дождётесь того, чего ждёте.
  2. Попробуйте сначала просто найти элементы с этим локатором: driver.FindElements(locator).
    Если они будут найдены, то значит проблема в том, что какому-то элементу из коллекции что-то мешает стать видимым.

Покажите локатор, по которому ищете.

Сейчас все начну проверять

А сам локатор? Который используется в переменной locator

namespace Benivo_test.Locators
{
    class NavToLogin_Locators
    {
        public static string emailTxt = "Email";
        public static string continueBtn = "fc-vip-default-btn";
        public static string welcomeTitlePath = "//h1[contains(., 'Welcome')]";
        //public static string requiredFieldMsg = "//span[contains(., 'Your email address is required.')]";
      // public static string notValidEmailMsg = "html/body/div[2]/div[2]/div/div/div[2]/div/form/div/div/span[2]";
        //public static string notRegisteredEmailMsg = "html/body/div[2]/div[2]/div/div/div[2]/div/form/div/div/span[3]";

        //there was a task to remove these links
        //  public static string clickHereLnk = "Click here";
        //   public static string learnMoreAbtBenivoLnk = "Learn more about Benivo";

        public static string errorMsg = "fc-vip-error-msg";
            //"form-group has-error";

    }
}




Попробуйте такой локатор:

By.XPath("//*[contains(@class, \'fc-vip-error-msg\')]")
2 лайка

Слетел:(

Вы явно что-то не так делаете.
У вас локаторы почему-то хранятся как переменные с типом string, а не с типом By.

Напишите вот так функцию для проверки:

 public string IsDisplayed(By locator, int avgWaitTime, int i)
        {
            try
            {
                wait = new WebDriverWait(driver, TimeSpan.FromMinutes(avgWaitTime));
                var errorMessages = 
 wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.XPath("//*[contains(@class, \'fc-vip-error-msg\')]")));
                var msgCount = errorMessages.Count;
                Assert.Equals(msgCount, 3);
                return errorMessages[i].Text;
            }
            catch (WebDriverTimeoutException)
            {
                return "Damn";
            }
        }
это на джаве но думаю суть понятна:

 private By errorMessages = By.xpath("//*[contains(@class, \'fc-vip-error-msg\')]"); - этот локатор найдет все три вэб-елемента которые могуть быть показаны в случае возникновения ошибки

    public boolean isErrorDisplayed() {

        List<WebElement> elements = driver.findElements(errorMessages); 

        //цикл в котором проверим отображается хоть какая то ошибка
        //если хоть какая то ошибка отображена значить вернуть 'true' иначе вернется 'false'
        for (int i = 0; i < elements.size(); i++) {
            if (elements.get(i).isDisplayed()) {
                return true;
            }
        }
        return false;
    }

 public String getErrorMessage(){
        List<WebElement> elements = driver.findElements(errorMessages);
        for (int i = 0; i < elements.size(); i++) {
            if (elements.get(i).isDisplayed())
                return elements.get(i).getText();
        }
        //здесь можно вернуть пустую строку или сообщение о  том что не было найдено ни одной
        //отображаемой ошибки
        //return "Не найдено отображаемой ошибки!!"
        return "";
    }

ну и сами шаги 
        driver.get("someURL");
        someClass.fillForm("someEmail");
        Assert.assertEquals(someClass.getErrorMessage(),"Your email address is required");

1 лайк

Не помогло. Сейчас попробую все написать заново

using Benivo_test.Locators;
using NUnit.Framework;
using OpenQA.Selenium;
using System;
using System.Threading;

namespace Benivo_test.POM
{
    class NavToLogin : BaseObjects
    {
        NavToLogin_Locators NavigateToLogin_Locators = new NavToLogin_Locators();

        private By _emailTxt = By.Name(NavToLogin_Locators.emailTxt);
        private By _continueBtn = By.ClassName(NavToLogin_Locators.continueBtn);
        private By _errorMsg = By.XPath(NavToLogin_Locators.errorMsg);
        private By _title = By.XPath(NavToLogin_Locators.welcomeTitlePath);
        //private By _requiredFieldMsg = By.XPath(NavToLogin_Locators.requiredFieldMsg);
        //private By _notValidEmailMsg = By.XPath(NavToLogin_Locators.notValidEmailMsg);
        //private By _notRegisteredEmailMsg = By.XPath(NavToLogin_Locators.notRegisteredEmailMsg);
     

        public NavToLogin(IWebDriver driver) : base(driver)
        {
            Console.WriteLine("Default Page opened");
        }

        //Checking all elements on the welcome page, which should exist
        public void WelcomePageOpened()
        {
            Assert.IsTrue(GetElement(_emailTxt).Displayed);
            Assert.IsTrue(GetElement(_continueBtn).Displayed);
            Assert.IsTrue(GetElement(_title).Displayed);
        }

        //Set user email in textbox
        public void FillData(string email)
        {
            SetElement(_emailTxt, email);           
        }

        //Click on continue button
        public void ClickOnContinueButton()
        {
            ClickOnElement(_continueBtn);
        }

        #region.not relevant anymore


        //Click on Click Here Link 
        //public EmpPage ClickHereLink()
        //{
        //    ClickOnElement(_clickHereLnk);
        //    return new EmpPage(driver);
        //}

        //Click on Learn More About Benivo Link 
        //public ContactPage LearnMoreAbtBenivoLink()
        //{
        //    ClickOnElement(_learnMoreAbtBenivoLnk);
        //    return new ContactPage(driver);
        //}

        #endregion

        //Filling form
        public LoginPage FillForm(string strUserEmail)
        {
            //Fill user email
            SetElement(_emailTxt, strUserEmail);
            //Click on continue button
            ClickOnElement(_continueBtn);
            return new LoginPage(driver);
        }


        //Get WarningMessage
        public string GetWarningMessage(string email, int i)
        {
            //return IsDisplayed(_errorMsg, 1, i);
            return IsDisplayed(_errorMsg, 1, i);

        }

    }
}