I am applying the selenium webdriverwait method to a particular IWebElement to fetch some child elements of this IWebElement when they are available. This is my code...
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IList<IWebElement> elementsA = wait.Until<IList<IWebElement>>((d) =>
{
return driver.FindElements(By.XPath("//table[#class='boxVerde']"));
});
foreach (IWebElement iwe in elementsA)
{
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IList<IWebElement> elementsB = wait.Until<IList<IWebElement>>((d) =>
{
return iwe.FindElements(By.XPath("tr/td/div/a"));
//trying to fetch the anchor tags from the element
});
}
it keeps giving me an error saying 'element no longer attached to DOM'...I think that the webdriver wait is simply not working. Am I doing anything wrong guys? much thanks in advance
It sounds like you are suffering from a Stale Element.
Every WebElement that Selenium finds is actually a reference to a element inside the DOM
Sometimes the JavaScript used on a site will destroy and recreate an element, when this happens your existing reference becomes stale and you will see a StaleElementReferenceException (At least that's what it's called in Java land, You should be seeing something very similar).
So if you ever see a StaleElementReferenceException or a message stating that the "element no longer attached to DOM", it means that the reference to an element in the DOM that you used to have is no longer valid because the element you had a reference to has been destroyed.
This isn't always obvious visually because the original element may have been destroyed and then an identical one recreated, it is however a new element so you need to create a new reference to interact with it.
The way to create a new reference is to find the element again.
It's not totally clear from your questions, but I am assuming you are getting the issue when iterating through the list of anchor elements after finding the table. If this is the case it suggests that the table has been destroyed and recreated between the point you found the table element and then started to iterate through the anchor elements inside the table.
If this is the case you will need to find the table again, a useful trick is to wait for the table to become stale before you try and find it again. This way you can be reasonably confident that any JavaScript on the page that is destroying the table and then re-creating it has finished processing. The .NET ExpectedConditions class is not as mature as the Java ExpectedConditions class. I would suggest having a look at some of the Java ones and porting them across to .NET (It should be fairly trivial, the structure is pretty similar), of particular interest is the Java one that waits for an element to become stale.
I believe that some of the tables has been removed for the page. It will be useful to look at events on your page. You should use //table[#class='boxVerde']/tr/td/div/a xpath instead of searching inside the element.
You have to define your Webdriver wait to ignore the Exceptions until the polling time overs. The following java method polls the element util 60 seconds and returns if it is loaded else will throws a Timeout Exception. Please convert this to your language as you needed.(Sorry,i am a javaist)
public WebElement fluentWait(final By locator, WebDriver driver) {
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(60, TimeUnit.SECONDS)
.pollingEvery(1, TimeUnit.SECONDS)
.ignoring(StaleElementReferenceException.class)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(
new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
} );
return foo;}
In addition to that if you are looking for a single anchor tag element use the xpath as
iwe.FindElements(By.XPath(" //a[text()='anchor tag text']"));
or Locate your element via By.linkText("anchor tag text");
iwe.FindElements(By.linkText("anchor tag text"));
Try using this. It waits for the Elements to be present within the page.
static void ForElementsArePresent(IWebDriver wd, double waitForSeconds, By by)
{
try
{
WebDriverWait wait = new WebDriverWait(wd, TimeSpan.FromSeconds(waitForSeconds));
wait.Until(x => (x.FindElements(by).Count > 0));
}
catch (WebDriverTimeoutException)
{
Console.WriteLine("Waiting for element " + by + " to disappear timed out after " + waitForSeconds + " seconds.");
throw;
}
}
Related
Guys, I have started to work on selenium web driver. You can assume I am a beginner. At the moment I am having difficulties in implementing the implicit wait command in my code (C#). it is not working as it should and result in an exception due to Element not found, however when I add the "Thread.Sleep(3000) the code get executed flawlessly. I have been looking for the solution all over the internet but not able to resolve the problem. Below I have mentioned sample code.
class Entrypoint
{
static void Main()
{
IWebDriver driver = new ChromeDriver();
**driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(20);**
driver.Navigate().GoToUrl("https://r1.netrevelation.com:8443/mcba-cms/pages/flight-transfer.cab");
driver.Manage().Window.Maximize();
driver.FindElement(By.Id("loginlink")).Click();
driver.FindElement(By.Id("headerSubView:inputUserName:input")).SendKeys("st001");
driver.FindElement(By.Id("headerSubView:inputPassword:input")).SendKeys("hello321" + Keys.Enter);
driver.FindElement(By.Id("dateOfFlight:input")).Click();**//This Step does not get Executed , it throws exception element not found.**
driver.FindElement(By.Id("ui-datepicker-div")).Click();
driver.FindElement(By.XPath(".//*[#id='ui-datepicker-div']/div/a[2]/span")).Click();
driver.FindElement(By.LinkText("28")).Click();
IWebElement Flightno = driver.FindElement(By.Id("selectedFlight:input"));
Flightno.SendKeys("BA901" + Keys.Enter);
IWebElement Flighttick = driver.FindElement(By.Id("flightTickImg"));
driver.Quit();
Please note that at the moment I don't want to use explicit wait, as implicit will serve my need (if it starts working). The above code Run in supersonic speed for somehow it manages to Login into the system but afterward it Fails every time reason being once Login request is made system pauses for 2-3 seconds. Please provide your comment in this regard.
As per the documentation, an Implicit Wait is to tell the WebDriver to poll the HTML DOM for a certain amount of time when trying to find an element() or find all elements() if they are not immediately available. But availability of an element in the DOM Tree doesn't guarantees that the ElementToBeClickable as you have tried in your code block. Hence you face the exception as Element not found.
Solution:
So the solution to your issue is to induce Explicit Wait i.e. WebDriverWait with ExpectedConditions clause as ElementToBeClickable which will not only confirm the availability of an element in the HTML DOM but also ensure that the Element is Clickable i.e. Element is Displayed and Enabled as follows:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement element = wait.Until(ExpectedConditions.ElementToBeClickable(By.Id("loginlink")));
I'm getting a StaleElementReferenceException (Element is not attached to the page document) whenever I try to use Actions to move to an element not on the page the driver is first loaded with; however, the element shows up in both the DOM and the page source. I'm using Selenium with ChromeDriver version 2.30. I've tried running Chome in headless mode as well. I've also tried to switch the binary to Chrome beta and Chrome Canary.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(d =>
{
try
{
IWebElement e = driver.FindElementById(ID);
builder.MoveToElement(e).Build().Perform();
builder.Click().Build().Perform();
return true;
}
catch { }
return false;
});
It tries multiple times to find the element, but never can; it hangs on MoveToElement and returns the exception. As you can see, I've already tried to wrap the whole thing in a try/catch loop; it still never gets the element. Any help would be appreciated!
Create a new Actions object. They're apparently page-specific, so the old one stops working after navigation.
builder = new Actions(driver);
I am completely new to Selenium, started using it yesterday and I am pretty much done with the first part of my project and I really love the way its going.
Altho I am having one problem, currently I am using Thread.Sleep for pauses until elements get present. There are some animations going on or just slow loading at times, how can I make it wait until the element is present and then interact with it?
For example:
LoginPageElements loginPage = new LoginPageElements();
loginPage.continueLink.Click();
Thread.Sleep(5000); //here it has to wait until the next page loads
ClickDailyBonusPopUp();
Driver.driver.Navigate().GoToUrl(.....);
Thread.Sleep(2000); //here it has to wait until a login form pops up
LoginFormElements loginForm = new LoginFormElements();
loginForm.userPasswordLogin.Click();
Thread.Sleep(2000); //here it has to wait until a different login form pops up
You need to use WebDriverWait class. Here is really good solution for your problem.
If your application uses jQuery, I would make use of Selenium's IJavaScriptExecutor to do something like this:
public void WaitForAjax()
{
if ((bool)((IJavaScriptExecutor)WebDriver).("return window.jQuery != undefined"))
{
while (true)
{
var ajaxIsComplete = (bool)((IJavaScriptExecutor)WebDriver).ExecuteScript("return jQuery.active == 0");
if (ajaxIsComplete)
break;
Thread.Sleep(100);
}
}
}
(More on jQuery.active here.)
The main idea is to find some condition or element to poll for/wait on that is always present when the page isn't ready.
I am new to selenium webdriver and am testing one application. In my application, I have to test about linking Facebook Account. Whenever I click on link the pop up will be displayed where I have to enter credentials. I am able to link sometimes and sometimes the test fails. I know the reason because it takes time to load pop up window and next command is executed so it is not able to find the element. I have used Thread.Sleep but I want to use implicit wait or explicit wait which is always a good practice rather than Thread.Sleep. How to use implicit wait and where to use that command exactly? Please advice. Thanks.
public void SocialFaceBook()
{
string currentWindow = driver.CurrentWindowHandle;
PopupWindowFinder finder = new PopupWindowFinder(driver);
string facebookWindow = finder.Click(driver.FindElement(By.XPath("//div[#id='panelFacebook']/div[2]/div[3]/div[3]/a")));
// Switch To FaceBook Window
driver.SwitchTo().Window(facebookWindow);
System.Threading.Thread.Sleep(3000);
// Link
// Email Address
IWebElement faceBookLinkEmail = driver.FindElement(By.Id("email"));
faceBookLinkEmail.SendKeys(SocialFaceBookEmail);
// Password
IWebElement faceBookLinkPass = driver.FindElement(By.Id("pass"));
faceBookLinkPass.SendKeys(SocialFaceBookPass);
// Log In Button
IWebElement faceBookLinkLogin = driver.FindElement(By.XPath("//input[#id='u_0_1']"));
faceBookLinkLogin.Click();
// Switch To Main Window
driver.SwitchTo().Window(currentWindow);
System.Threading.Thread.Sleep(3000);
// Sync
IWebElement faceBookSync = driver.FindElement(By.XPath("//div[#id='panelFacebook']/div[2]/div[3]/div[2]/a"));
faceBookSync.Click();
// Unlink
IWebElement faceBookUnLink = driver.FindElement(By.XPath("//div[#id='panelFacebook']/div[2]/div[3]/div[1]/a"));
faceBookUnLink.Click();
}
Sometimes it is not able to find the log in details as pop up is not loaded properly and sometimes it is not able to find sync button as facebook account takes time to link. Please advice.
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("locator")));
It will wait for the element to be located for a maximum of 30 seconds if the element is found before that it will execute....
I had to change some small things from #Vicky's answer but this is what I got as a method I could call.
public static void WaitForElementLoad(By by, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromSeconds(timeoutInSeconds));
wait.Until(ExpectedConditions.ElementIsVisible(by));
}
}
and I call it like this:
MyClass.WaitForElementLoad(By.CssSelector("div#div1 div strong a"), 10);
I used to write a function to detect an element exists every second. if find continue, otherwise threw timeout error. but in that function i still use Thread.Sleep.
Expect other good solution.
I use ExpectedCondition.visibilityOf(element) instead of thread sleeps
Implicit wait -- max waiting time to identify object, it will identify the object for every 500 ms. if it fails to identify the object with in maximum time it will throw nosuchelement exception.
Explicit wait -- used for ajax page loads for the same purpose.
maximum waiting time is same as thread.sleep
Wrote a method for a project:
public static void WaitForElementPresentBy(By by)
{
try
{
Wait.Until(ExpectedConditions.ElementIsVisible(by));
}
catch (TimeoutException te)
{
Assert.Fail("The element with selector {0} didn't appear. The exception was:\n {1}", by, te.ToString());
}
}
Wait should have already been defined.
I have the following scenario:
I want to navigate to a page. Then click a button as soon as it appears(not wait for page to load ). I don't want to wait for the initial page to load as it takes a long time. My program currently is stuck until the page loads and then clicks the button.
I basically want to navigate to link and then have no wait for page and continue with my code.
Is there anyway round this?
With the latest version of the .NET bindings, you can set a page load timeout. However, there are some caveats you'll need to be aware of. First, this hasn't been implemented by all browsers. It should work for IE and Firefox, if memory serves. Secondly, you'll need to catch an exception to make that work properly, but it can be done.
// WARNING! Completely untested code written without
// the benefit of an IDE!
IWebDriver driver = new InternetExplorerDriver();
driver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(1));
try
{
driver.Url = "http://your.long.loading.page.com";
}
catch (TimeoutException)
{
// NOTE: In 2.26 or later, this will be WebDriverTimeoutException
}
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement element = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("yourId"));
}
IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("someDynamicElement"));
});
It does exactly what you want. It queries the page to find the element, catches exceptions if no element found and returns an element when found.
After that, you can manipulate the button ignoring the fact that page can be not loaded
http://seleniumhq.org/docs/04_webdriver_advanced.html
Short answer: No.
Long answer: Selenium is by default trying to simulate the real user - I know that it kinda sucks, especially at a times you need to test a deploy after deploy after deploy...
But: If real user has to wait for button to appear, then the program has to do it also...
BTW: If the button really appears among first on the page, you can try this:
search for the button by ID, xpath ... the way you do it
Catch exception (I am Java guy, so dont ask me how)
If there was error, wait short time (e.g. 200 milliseconds) and then go to 1
If not, click the button
The cycle should end also if certain amount of time passes (10s) and if so, throw exception
As stated above: Language of my choice is Java. There I can do that. But I dont know how to write that in C#