1

I am trying to get my code to wait for an element to appear before trying to get the text from the element. If I step through the code allowing the element time to appear it works as expected, but if I run it without breakpoints the wait appears to be ignored and an exception is raised.

I don't understand why it is being ignored?

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
IWebElement message = wait.Until(driver => driver.FindElement(By.ClassName("block-ui-message")));
string messageText = message.Text;
Litisqe Kumar
  • 2,512
  • 4
  • 26
  • 40
Northers
  • 85
  • 1
  • 13

2 Answers2

2

As an alternative you can induce WebDriverWait for the ElementIsVisible() and you can use the following Locator Strategy:

string messageText = new WebDriverWait(driver, TimeSpan.FromSeconds(30)).Until(ExpectedConditions.ElementIsVisible(By.ClassName("block-ui-message"))).GetAttribute("innerHTML");

Using DotNetSeleniumExtras.WaitHelpers with nuget:

Not that super clear what exactly you meant by specific using directive I need. In-case you are using SeleniumExtras and WaitHelpers you can use the following solution:

string messageText = new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.ClassName("block-ui-message"))).GetAttribute("innerHTML");
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • I tried this one out, but was getting an issue with the `ExpectedConditions` part - is there a specific `using` directive I need? – Northers Aug 19 '19 at 10:18
  • @Northers Checkout the updated answer and let me know the status. – undetected Selenium Aug 19 '19 at 10:31
  • I get the same issue, just worded differently - 'The name SeleniumExtras does not exist in the current context' – Northers Aug 19 '19 at 11:10
  • Seems you are messing up a couple of things here: 1) You started your question with _"element to appear"_ 2) Using _ExpectedConditions_ you spoke about _`directive`_ 3) Using _SeleniumExtras.WaitHelpers_ you are saying _...The name SeleniumExtras does not exist..._. 4) In the other answer you mentioned _interact with the element_. What is your exact usercase? What are the _manual Steps_ which you are trying to _Automate_? – undetected Selenium Aug 19 '19 at 11:17
  • Okay, I just need to wait until an element is visible on screen so I can interact with it, in this case I need to extract the text from the element. The element does eventually appear on screen and I can get the text easily enough if I step through the execution, I just need the code to wait until the object is present in a way that I can interact with it so that it will run without me stepping through it. – Northers Aug 19 '19 at 12:44
  • Regarding the issue with ExpectedConditions or SeleniumExtras, is there a `using` statement I can add to the top of my code to make either of them work? – Northers Aug 19 '19 at 12:47
  • @Northers Update the main question with all these relevant information which you have mentioned as comments. – undetected Selenium Aug 19 '19 at 12:48
  • I have your code working now. I am using Selenium 3.14 and ExpectedConditions has been removed so I installed the DotNetSeleniumExtras package and now your code works, thank you. I don't believe my original question needs to be changed as all the relevant detail is still present. – Northers Aug 19 '19 at 13:00
0

Below sample code will wait until the element is presented

        private bool IsElementPresent(By by)
        {
            try
            {
                _driver.FindElement(by);
                return true;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
        }

        private void WaitForReady(By by)
        {
            var wait = new WebDriverWait(_driver, TimeSpan.FromHours(2));
            wait.Until(driver =>
            {
                //bool isAjaxFinished = (bool)((IJavaScriptExecutor)driver).ExecuteScript("return jQuery.active == 0");
                return IsElementPresent(by);
            });
        }

      // ...
      // Usage
      WaitForReady(By.ClassName("block-ui-message")); // It will wait until element which class name is 'block-ui-message' is presented to page
  • This approach works fine, thank you. Do you know why my approach was not working? – Northers Aug 19 '19 at 10:18
  • @Northers When you create your own `ExpectedCondition` via lambda function it works in different manners. In your case, Selenium expected either `IWebElement` or `null`. However, it got `NoSuchElementException`. If you'd just put your code in `try-catch` block like SuxrobGM did, it would work – Fenio Aug 19 '19 at 10:38
  • Okay, I was premature in my response - using the above code no longer gives me an exception and does indeed wait for the element to be present, but only present in the DOM so I cannot interact with the element at that time. Are there alternatives to FindElement that will ensure the code waits for the element to actually be visible on screen and therefore allow interaction? – Northers Aug 19 '19 at 11:07
  • Use asynchronous methods. Change above code and implement `async/await` methods – Sukhrob Ilyosbekov Aug 19 '19 at 11:49