How can I check that the page was loaded with Selenium - c#

I am looking for a way to check that the page was loaded using Selenium. So basically does the url point to a correct address (in chrome the browser shows something like this) :
I am using the following code:
var driver = new FirefoxDriver();
driver.Url = "SomeUrl";
Currently I am comparing the title to "SomeUrl is not available" and if it matches I mark that the page has failed to load.
But is there a better way?

I would suggest, if you know what control ID/or link or/Class is going to appear on your page. Then wait for that element to appear on screen for a defined period of time.
I that element appears then your next line of code will be executed
Here is the simple version of m method. You can make it more dynamic based on your need.
/// <summary>
/// WaitForElementOnPage() method waits a passed number of seconds for the existence
/// of a passed IWebElement object. If the object is found the method return an IWebElement of the object
/// If the object is not found in the passed number of seconds, the method returns a null IWebElement
/// </summary>
public IWebElement WaitForElementOnPage(string controlID, int waitTime)
{
IWebElement element = null;
IWebElement elementFound = null;
try
{
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(waitTime));
Thread.Sleep(3000);
elementFound = wait.Until<IWebElement>((d) =>
{
element = d.FindElement(By.Id(controlID));
break;
return element;
});
}
catch (Exception ex)
{
Log.Error(ex);
elementFound = null;
}
return elementFound ;
}

I personally try to locate body or frameset element on the page.
Based on my experience while using selenium with chromedriver, page content sometimes doesn't show up and I need to run webdriver.refresh() 1-2 times. It doesn't happen all the time, but I run big amount of chrome instances on one machine and this approach was the most effective for now to avoid this.
So I try to locate body or frameset elements and reload few times before I give up.
The advantage of this solution is also the fact that it will also work in case Chrome changes its messages in the future. It will also work with other browsers.

Related

Selenium PageFactory lazy evaluation StaleElementException

I'm doing unit testing on a system using Selenium with a Page Object Model.
Usually I'm able to figure out a solution to such a problem in relatively short order, but this one is being rather tenacious, so I thought I should just get clarification on the root of the problem rather than write another workaround.
There is some PageObject class that has an IWebElement property with the necessary FindsBy attribute for locating a element on the page, and a method that uses said property:
public class Foo : BasePage
{
...
[FindsBy(How = How.XPath, Using = "//a[#title='Edit']")]
protected IWebElement LinkEdit { get; set; }
...
public Bar ClickEdit()
{
WaitUntilInteractable(LinkEdit);
LinkEdit.Click();
return new Bar(driver);
}
...
}
Note that this is the only reference to LinkEdit
For clarity, WaitUntilInteractable is defined in BasePage as:
protected void WaitUntilInteractable(IWebElement webElement)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
_ = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(webElement));
}
My understanding of how the PageFactory works with Selenium is that whenever you reference a IWebElement property of a class, the IWebDriver will then find the element within the page.
This much is said on this page: https://github.com/seleniumhq/selenium/wiki/pagefactory
... every time we call a method on the WebElement, the driver will go and find it on the current page again.
Given that knowledge, I don't quite understand how I can run into StaleElementReferenceException when simply referencing one of these properties. Surely either the element cannot be found, in which case a NoSuchElementException will be thrown, or it can be found, in which case it is present on the document, and not "stale".
Perhaps I've misunderstood staleness.
A StaleElementException occurs when the element being reference is no longer attached to the HTML document. This can happen in amazingly small amounts of time, and generally occurs when JavaScript is updating the page. As a further frustration, the WebDriverWait object does not catch StaleElementException's and continue waiting. You must tell WebDriverWait to ignore these exceptions:
protected void WaitUntilInteractable(IWebElement webElement)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.IgnoreExceptionTypes(typeof(StaleElementException));
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(webElement));
}
Now when webElement is stale, it retries the operation until the wait object times out.

ImplicitWait does not seem to work in Selenium Webdriver to wait for elements

I am trying to automate the Internet Explorer in c# using selenium-webdriver to fill a formular on an external website.
Sometimes the code throws randomly errors (Unable to find element with name == xxx), because it cannot find the searched elements. It's not happening every time and not necessarily in the same places.
I've already tried setting an implicitWait with the following code which reduced the number of errors.
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
The external webpage changes the selection options (through reloading) from Dropdowns after selecting an option from another Dropdown.
To additionally intercept these critical points, I wait 2 seconds before trying to find the Dropdown-options ByName().
System.Threading.Thread.Sleep(2000);
The webpage takes less than half a second to reload this Dropdowns, so that 2 seconds should be enough.
Can you tell me what i'm doing wrong or why the webdriver seems to run so instably finding elements.
I have also noticed that I am not allowed to do anything else on the computer as long as the program is running, otherwise the same error occurs more often.
My driver-options for internet explorer 8
var options = new InternetExplorerOptions()
{
InitialBrowserUrl = "ExternalPage",
IntroduceInstabilityByIgnoringProtectedModeSettings = true,
IgnoreZoomLevel = true,
EnableNativeEvents = false,
RequireWindowFocus = false
};
IWebDriver driver = new InternetExplorerDriver(options);
driver.Manage().Window.Maximize();
My final solution working perfectly without a single error in more than 20 tests!
Added the following in the class
enum type
{
Name,
Id,
XPath
};
Added this behind my driver
driver.Manage().Window.Maximize();
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
Methode to wait for an element
private static void waitForElement(type typeVar, String name)
{
if( type.Id)wait.Until(ExpectedConditions.ElementToBeClickable(driver.FindElement(By.Id(name))));
else if(type.Name)wait.Until(ExpectedConditions.ElementToBeClickable(driver.FindElement(By.Name(name))));
else if(type.XPath)wait.Until(ExpectedConditions.ElementToBeClickable(driver.FindElement(By.XPath(name))));
}
And call the methode before calling any event with the element
waitForElement(type.Id, "ifOfElement");
You can use Explicit wait like this example:
var wait = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(10));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("your locator")));
You have two more options in Selenium:
You can use explicit wait via the WebDriverWait object in Selenium. In this way you can wait for elements to appear on the page. When they appear the code continues.
An example:
IWebDriver driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://yourUrl.com");
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMinutes(1));
Func<IWebDriver, bool> waitForElement = new Func<IWebDriver, bool>((IWebDriver Web) =>
{Console.WriteLine(Web.FindElement(By.Id("target")).GetAttribute("innerHTML"));
});
wait.Until(waitForElement);
Furthermore you can use the FluentWait option. In this way you can define the maximum amount of time to wait for a condition, as well as the frequency with which to check the condition.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function<WebDriver, WebElement>()
{
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});

Protractor seems not to wait

Working with Protractor by Bruno Baia v0.9.2 Selenium Webdriver v3.0.1 Selenium.Webdriver.ChromeDriver v2.27.0
I'm facing the following problem. I'm logging in from a non Angular page. When I'm on the first Angular page of my application I want to click on the first row of a NgRepeater on the page as follows:
class CarCompanies
{
NgWebDriver driver;
[FindsBy(How = How.XPath, Using = "Bedrij")]
private IWebElement linkBedrijven;
public bool ContainsText(string text, string heading)
{
return SelecteerElement.pageContainsHeadingElementWithText(driver, text, heading);
}
public void ClickFirstCar()
{
driver.FindElements(NgBy.Repeater("dmsInstance in dmsInstanceList"))[0].Click();
}
public CarCompanies(NgWebDriver driver)
{
this.driver = driver;
PageFactory.InitElements(driver, this);
}
}
This works fine when the preceding statement is a Thread.Sleep() but without this unwanted Sleep an IndexOutOfRangeException appears. The driver tells meIgnoreSynchronisation = false isAngular2 = false.
What am I doing wrong?
I'm guessing the element is not there yet when you call FindElements without the sleep. You should wait for the element to be there before looking for it.
Most probably using
driver.WaitForAngular();
will solve the issue (the methods waits for angular to finish loading).
If not, you can set an implicit wait or write an extension to wait while finding the element.
By the way, there is no need in your case to use FindElements(By)[0], method FindElement will return the first element in the DOM.

Selenium c# custom expected conditions for innerText

the html
<span id="banner">Rolling in 10.00...</span>
my code
public void waitroller()
{
Console.WriteLine("waiting roller");
WebDriverWait wait = new WebDriverWait(PropertiesCollection.driver, TimeSpan.FromDays(2));
wait.Until<IWebElement>((d) =>
{
IWebElement element = PropertiesCollection.driver.FindElement(By.Id("banner"));
if (element.Text == "Rolling in 20.00...")
{
return element;
}
return null;
});
}
OR
public void waitroller()
{
new WebDriverWait(PropertiesCollection.driver, TimeSpan.FromMinutes(1.5)).Until(ExpectedConditions.TextToBePresentInElementLocated(By.Id("banner") , "Rolling in 20.00..."));
}
I'm stuck with this innertext because the innertext in the html is always changing and i want to make a webdriverwait that waits until the innertext in the span banner is "Rolling in 20.00" . Is there any way to make custom expected conditions because I am not understand custom expected condition.
what i need is something like this
new WebDriverWait(PropertiesCollection.driver, TimeSpan.FromMinutes(1.5)).Until(ExpectedConditions.TextToBePresentInElement(PropertiesCollection.driver.FindElement(By.Id("banner"), "Rolling in 20.00...");
but this is not work because i think the id="banner" is innerText
there is one way that work but can't work for long because i think it is the wrong way of doing it . i loop the element banner many times and check if the innerText is equals to "Rolling in 20.00..." but have error also
public void waitroller()
{
Console.WriteLine("waiting roller");
WebDriverWait wait = new WebDriverWait(PropertiesCollection.driver, TimeSpan.FromDays(2));
IWebElement bannerElement = PropertiesCollection.driver.FindElement(By.Id("banner"));
wait.Until((d) =>{ return bannerElement.Text.Contains("Rolling in 20.00"); });
}
I don't know what you mean by "innertext", but with Selenium's WebDriverWait you can wait for whatever you want. You don't have to use the ExpectedConditions, they're only for programmers' comfort.
Example:
new WebDriverWait(...).Until(driver => driver.FindElement(...).Text.Equals(...));
On the other hand, your problem might be a completely different one. Is your "roller" a countdown where the text changes very fast? In this case you might never reach the expected condition. I think Selenium checks the expected conditions every 500 milliseconds, so it doesn't even notice when "Rolling in 20.00" is displayed for just let's say 50 millisecods and then has already changed to "Rolling in 19.95" when Selenium checks for the next time.

How to override Selenium Webdriver FindElement and add a wait to it?

I'm using Selenium Webdriver with C# and I'm wondering if there's a way to override the FindElement method? What I'd like to do - if possible - is to add an extra parameter and code to the method that would force it to wait for the element to be visible before proceeding.
For example, it would then be something like this:
Driver.FindElement(By.Id("orion.dialog.box.ok"), 60).Click();
This would wait up to 60 seconds for the element to appear and be available to click.
Any ideas how to do this?
Thanks,
John
You could use ImplicitWait for this. You can create a new user defined function to accept the By object and the timeout seconds and have the function return the IWebElement, something like below:
IWebElement elem = MyOwnGetElement(By.id("test"),60);
The above function might have the below code, where time_out_sec is the function parameter.
WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(time_out_sec));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));
I would suggest you add it as an extension method. Pseudo code:
public static IWebElement WaitForAndFindElement(this IWebDriver driver, By by)
{
// do a wait
// something like...
WebDriverWait wait = new WebDriverWait(TimeSpan.FromSeconds(60)); // hard code it here if you want to avoid each calling method passing in a value
return wait.Until(webDriver =>
{
if (webDriver.FindElement(by).Displayed)
{
return webDriver.FindElement(by);
}
return null; // returning null with force the wait class to iterate around again.
});
}
Just to state, an implicit wait is going to be part one of your solution. It will cause Selenium to wait up to 60 seconds for an element to be present in DOM but being visible is something entirely different.
.Displayed will handle that, and it must be handled within a WebDriverWait.
I am coding with Selenium for 6+ months and I had the same problem as yours. I have created this extension method and it works for me every time.
What the code does is:
During 20 seconds, it checks each 500ms, whether or not the element is present on the page. If after 20 seconds, it's not found, it will throw an exception.
This will help you make a dynamic wait.
public static class SeleniumExtensionMethods {
public static WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
public static void SafeClick(this IWebElement webElement) {
try {
wait.Until(ExpectedConditions.ElementToBeClickable(webElement)).Click();
} catch (TargetInvocationException ex) {
Console.WriteLine(ex.InnerException);
}
}
and then use it like this:
IWebElement x = driver.FindElement(By.Id("username"));
x.SafeClick();

Categories

Resources