Problem using Selenium to automate a postback link that is inside an ASP.NET UpdatePanel [duplicate] - selenium

This question already has answers here:
Selenium IDE click() timeout
(2 answers)
Closed 3 years ago.
I have a GridView control with sorting enabled inside an UpdatePanel. I used Selenium IDE to record a test that clicks on the sort link of the table, but when I try to execute the test it get's stuck on the click command. Looking at the log I see:
[info] Executing: |click | link=Name | |
[error] Timed out after 30000ms
I haven't tried it with Selenium-RC yet, I don't know if it will be any different. I don't want Selenium to wait for anything. Any ideas of how to work around it?
Thanks!

when using selenium + Ajax (or the page just get refresh under certain conditions).
I usually use:
selenium.WaitForCondition
or I created the following code recently (the page uses frames).
public bool AccessElementsOnDynamicPage(string frame, Predicate<SeleniumWrapper> condition)
{
DateTime currentTime = DateTime.Now;
DateTime timeOutTime = currentTime.AddMinutes(6);
while (currentTime < timeOutTime)
{
try
{
SelectSubFrame(frame);
if (condition(this))
return true;
}
catch (SeleniumException)
{
//TODO: log exception
}
finally
{
currentTime = DateTime.Now;
}
}
return false;
}
public bool WaitUntilIsElementPresent(string frame, string locator)
{
return AccessElementsOnDynamicPage(frame, delegate(SeleniumWrapper w)
{
return w.IsElementPresent(locator);
});
}
public bool WaitUntilIsTextPresent(string frame, string pattern)
{
return AccessElementsOnDynamicPage(frame, delegate(SeleniumWrapper w)
{
return w.IsTextPresent(pattern);
});
}
Soon you will get to the point you will need selenium RC integrated on your development environment, for this I recommend you to read:
How can I make my Selenium tests less brittle?
It is around waiting but for specific elements that should be (or appear) on the page.

Related

wait until invisibility using page factory doesn't work [duplicate]

This question already has answers here:
How to wait for invisibility of an element through PageFactory using Selenium and Java
(4 answers)
Closed 2 years ago.
I have this code:
#FindBy(how = How.CLASS_NAME, using = "loading-class")
WebElement loadingAnimation;
When I try to use this line:
waitDriver.until(ExpectedConditions.invisibilityOf(this.loadingAnimation));
It throws exception:
org.openqa.selenium.TimeoutException: Expected condition failed: waiting for invisibility of Proxy element for: DefaultElementLocator 'By.className: loading-container' (tried for 30 second(s) with 500 milliseconds interval)
for some reason it works when I debug the code.
I should mention that this works also:
while(true)
{
try {
this.loadingAnimation.isDisplayed();
}
catch (Exception e) {
break;
}
}
How to make it work using Page Factory?
When you implement Page Object pattern and initialize your page with PageFactory Selenium offers you the capability of using custom ElementLocator. There is AjaxElementLocator that is supposed to be used for dynamic elements.
In order to apply your own logic of how to consider your element ready for use, there is a method which default implementation is
protected boolean isElementUsable(WebElement element) {
return true;
}
So you are free to override that one to implement your condition. In a nutshell you need to implement your custom ElementLocatorFactory which would be producing AjaxElementLocator objects with your customized isElementUsable method. Then you would initialize your page with
public class YourPage{
...
public YourPage(...){
PageFactory.initElements(new YourCustomLocatorFactory(...), this);
}
...
}
You can find here the completed example of how to wait for certain state of dynamic elements of your page objects not using ExpectedConditions utility.

WebDriverWait times out when run through Continuous Integration

I use the following code to check if an element is visible for my automated tests before interacting with them (Selenium/C#).
public bool ElementVisible(IWebDriver driver, IWebElement element, int secondsToWait = 30, bool doNotFailTest = false)
{
try
{
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(secondsToWait));
wait.Until<IWebElement>(d =>
{
if (element.GetCssValue("display") != "none" && element.Size.Height > 0 && element.Size.Width > 0)
{
return element;
}
return null;
});
return true;
}
catch (Exception)
{
if (!doNotFailTest)
{
throw;
}
return false;
}
}
The tests that use this method work every time, when I run tests on my PC. However, when I trigger the tests to be run on our build machine from TFS's Continuous Integration, only then does this method time out when called by my tests. Another point that might be worth noting is: this method works on other websites we test (both locally and through the CI). Just not this one website for some reason...
I have tried:
Running the tests locally on the build machine, cutting out the CI = no issue.
Increased the time out several times to greater values = method times out at the greater values.
Added Thread.Sleep wait before the above try/catch block (my reasoning for this stems from an issue I found on Browserstack whereby an AJAX injected element would not be found by this method alone without first adding an arbitrary wait before the WebDriverWait... which doesn't make sense to me because WebDriverWait is apparently the only thing I need to use to find AJAX injected elements (from what I've read anyway)).
As an aside, the reason I've made this method a bool is because not all of my tests should fail if certain elements aren't found. For example, our website rarely has the terms and conditions updated. When it does, a modal is presented to the user when logging in. We've left this as a manual test, but to prevent this modal from breaking the daily runs, we look for it and accept the terms if it's there (suppressing exceptions).
This timeout error relates to an element of the test we do actually want to find, it is the condition to pass our LogIn test by finding an element on our website that is only present when logged in. This element is injected with AJAX.
Better colleagues than me at CI can't pinpoint why this issue is occurring. Theoretically, the trigger from the CI is simply to initiate the test run - it has no other involvement in the running of the tests...?
I have observed that when triggering the test run from the CI to the build machine, when I VPN to the build machine, I expect to see the browser load up and the tests being conducted, but this is not the case. Maybe this is a factor? Perhaps I'm wrong but this behaviour seems like the tests are running on a headless browser? Yet we have not specified any settings to use a headless version of Chrome (v75).
If it was the case that testing through a headless browser throws timeout errors related to AJAX elements, other tests have passed after logging in - using other AJAX injected elements. It is only when any test calls this method, does it time out, when the run is triggered from the CI, on this specific website.
Very confusing!
I created a JavaScript version of the WebDriverWait, added some debugging (Console.Error.WriteLine()) to output the element's computed styles. The display property was 'none'... however, when I log in manually, in Chrome's developer tools, it is 'block'. Weird.
The element I was looking for was a DIV container that has the class 'loggedin'. I instead passed through an element inside this container that would also only be displayed when logged in (a piece of text). This worked.
My WebDriverWait doesn't work with either of the elements, so I have to stick with this JavaScript alternative. One thing to note, however, is that the evaluation of the element's properties takes 5 seconds, so I've omitted setting an interval between checks.
public bool ElementVisible(IWebDriver driver, By locator, int numberOfPolls = 10, bool doNotFailTest = false)
{
bool elementVisible = false;
int pollCount = numberOfPolls;
Thread.Sleep(1000);
while (!elementVisible && pollCount > 0)
{
try
{
// Takes 5 seconds to compute, bear this in mind when setting an interval or increasing the pollCount
elementVisible = (bool)js.ExecuteScript("var display = window.getComputedStyle(arguments[0]).display; var height = window.getComputedStyle(arguments[0]).height; var width = window.getComputedStyle(arguments[0]).width; return (display != 'none' && height != 0 && width != 0);", driver.FindElement(locator));
}
catch (Exception)
{
}
if (elementVisible)
{
break;
}
pollCount--;
}
if (!elementVisible)
{
if (!doNotFailTest)
{
throw new Exception("ElementVisible(): - element not visible.");
}
}
return elementVisible;
}

I wrote a function for window handling but it's not working in selenium webdriver

I am working on Selenium webdriver and I have write a function for window handling. I have written code for naukri.com popup handling. My scenario is to Open the naukri.com and without closing popup window. I want to switch main window and click on Login button.I have written the code and created a function. when I am running the script focus is going on main page and url is displayed as selected but I am not able to click on Login button. I am not understanding where the problem is.Please suggest me.
public static WebDriver fn_SetFocus_According_Title(WebDriver dObj, String arg_title)
{
Set<String> setcol_windowHandle=dObj.getWindowHandles();
Iterator<String>itcol_handleval=setcol_windowHandle.iterator();
while(itcol_handleval.hasNext()==true){
String windowhanldval=itcol_handleval.next();
dObj=dObj.switchTo().window(windowhanldval);
String apptitle=dObj.getTitle();
if(apptitle.contains(arg_title))
{
dObj=dObj.switchTo().window(arg_title);
}
}
return dObj;
}
}
WebDriver dObj = new FirefoxDriver();
dObj.manage().window().maximize();
dObj.get("https://www.naukri.com");
dObj.manage().timeouts().implicitlyWait(60,TimeUnit.SECONDS);
dObj=fn_SetFocus_According_Title(dObj,"Jobs - Recruitment - Job Search - Employment - Job Vacancies - Naukri.com");
dObj.findElement(By.xpath("//a[#id='login_Layer']")).click();
Make the following changes in your code:
Change to:
dObj.switchTo().window(windowhanldval);
Reduce the actual string of "arg_title" as you would be looking for this entire string within the String obtained by getTitle()
When you are already on that page trying to match the page title which means the focus is already on the actual page where we need to locate the Login button element. So remove the second switch () line entirely. Rather use "break" to come out if loop.
Let me know if these steps works for you.
The function below works for me.
public static void switchToWindow(String windowTitle)
{
for (String window : driver.getWindowHandles())
{
driver.switchTo().window(window);
if (driver.getTitle().equals(windowTitle))
{
return;
}
}
throw new InvalidParameterException("The window titled <" + windowTitle + "> does not exist.");
}
One issue you may run into is that when a new tab/window is created, you may need to wait for it to appear. To do that, you can use something like
int count = driver.getWindowHandles().size() + 1; // add 1 to the current window count
// do something that spawns a new window
new WebDriverWait(driver, 3).until(ExpectedConditions.numberOfWindowsToBe(count));
You don't need to return the WebDriver instance. It's the same driver instance you are already using. If the expected window title is not found, the function will throw an exception.
Hope this will work for you.
public void Parenthandle(WebDriver wb){
try {
String ParentPageHandle = wb.getWindowHandle();
for (String newPage : wb.getWindowHandles()) {
if (!ParentPageHandle.equals(newPage)) {
wb.switchTo().window(newPage);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
}

Selenium extremely slow on reading the DOM

Selenium interaction with DOM seems extremely slow while doing couple of things in every page instantiation. Throughout the site we have visible spinner that indicates any outstanding API calls resolved or not. In summary I have three methods that make sure the stability of page before performing any action.
Check for the DOM ready state
Check for any outstanding JQuery calls
Check for loading spinners
All of these three are done as a part of the page object instantiation with following methods.
public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver){
final WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(waitForDomReadyState());
wait.until(waitForjQueryToBeInactive());
List<WebElement> elements = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(spinnersLoacator));
for(WebElement element: elements){
wait.until(invisibilityOfElementLocated(element));
}
}
private static ExpectedCondition<Boolean> waitForDomReadyState(){
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver d){
return ( ((JavascriptExecutor) d).executeScript("return document.readyState;").equals("complete"));
}
};
}
private static ExpectedCondition<Boolean> waitForjQueryToBeInactive(){
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver d){
return (Boolean) ( ((JavascriptExecutor) d).executeScript("return jQuery.active == 0;"));
}
};
}
public static ExpectedCondition<Boolean> invisibilityOfElementLocated(final WebElement element){
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driver){
try{
return !element.isDisplayed();
} catch (NoSuchElementException | StaleElementReferenceException e){
// Returns true because the element is not present in DOM.
// The
// try block checks if the element is present but is
// invisible or stale
return true;
}
}
};
}
Taking an example of a page(say patient page) which has good number of API calls and fetches a lot of data. For a initial class instantiation it takes about 17s(log below). My Selenium knowledge says, the subsequent page instantiation should not take same or more time to check DOM ready state, or JQuery call or spinner waits since there is nothing changing at all. However, every time new page instantiate I see it takes same amount of time taken to check all these three. What's happening there? Does Selenium actually tries to interact with Server every time I do these or just interaction with the client is slow for some reason? If so, what could be the possible answer?
Console log
==== [[Finished waiting for 8 spinner elements found on widget [Patient] after [17] s]]
==== [[Start waiting for 8 spinner elements found on widget [Patient] ]]
==== [[Finished waiting for 8 spinner elements found on widget [Patient] after [17] s]]
==== Browser on [[[Patient]]]
==== [[Start waiting for 8 spinner elements found on widget [Patient] ]]
==== [[Finished waiting for 8 spinner elements found on widget [Patient] after [17] s]]
Environment:
Selenium 2.48
Firefox 38
I also tried with Selenium 2.52 and firefox 44 with same result
Selenium handles all the waiting on the client side with a request sent to the server for every evaluation until the condition is met.
It can quickly degenerate in case of high latency, especially if there are a lot of calls. Moreover some evaluations require a script injection which doesn't help either.
So the best way to improve the performance in your case would be to use a single asynchronous JavaScript call:
public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver) {
const String JS_WAIT_SPINNERS =
"var callback = arguments[0]; " +
"(function fn(){ " +
" if (document.readyState == 'complete' && jQuery.active == 0) { " +
" var elts = $('.spinners'); " +
" if (elts.length == 8 && !elts.is(':visible')) " +
" return callback(); " +
" } " +
" setTimeout(fn, 60); " +
"})();";
((JavascriptExecutor)driver).executeAsyncScript(JS_WAIT_SPINNERS);
}
To initialize the timeout:
driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
Your test seems to be all non-native calls and so Firefox should work for you but I am surprised that the Firefox native call to driver.navigate() even worked for you to get to the inital page if you were using 44 and 48. It is well known that 31.6.0 was the last supported native Firefox version. So, I would say you should use Chrome until you figure this out.
But, to answer your thing about slowness. The way you wrote your code, you are highly dependent on jQuery and I would imagine your are having an issue with your calls to jQuery code being delayed, which propagates out to your Selenium test, and further impacted by the fact that your looping through multiple spinners. One thing I have noticed before is that if a page is busy running ajax calls, then your Selenium calls with JavascriptExecutor might have to wait in line for those to give up bits of processor time.
What would I do differently?
Well, I would write my spinner waits to operate on the DOM instead of calling JavascriptExecutors to jQuery. Maybe in your case, this is not an option, but I think a well thought out plan can improve the efficiency of your page ready workflow.

Using Selenium Webdriver to do an action if a condition is met

I am using selenium to perform repetitive tasks on a website - a very useful feature for automating web tasks.
I am stuck on how to perform an action only if certain text is present on the page. Is this possible?
I do not want the lack of text to break the test case - only to bypass the action.
I have the Flow Control plugin too, but havent figured out how to make this do any more.
In Java you can make a method that returns true or false whether an element is present or not :
public boolean isElementPresent(By by) {
try {
return driver.findElement(by) != null;
} catch (NoSuchElementException e) {
return false;
}
}
And concerning the text you want to find you can do :
if(isElementPresent(By.xpath("//*[contains(text(),'Some text')]"))){
// Do your tests here
}