Unpredictable behaviour with Selenium and jUnit - selenium

I am working on a website and trying to test it with Selenium and jUnit. I'm getting race conditions between the test and the site, despite my best efforts.
The front end of the site is HTML and jQuery. The back end (via AJAX) is PHP.
The site
I have two required text input fields (year and age), plus some others that I'm not changing in the tests that give problems. As soon as both text inputs are non-empty, an AJAX call is made to the back end. This will return 0+ results. If 0 results are returned, a results div on the screen gets some text saying that there were no results. If >0 results are returned, a table is written to the results div showing the results.
I don't want the site to wait until e.g. 4 digits' worth of year is entered before doing the AJAX call as it could be looking at ancient history (yes, really). So, as soon as both are non-empty the call should be made. If you type slowly, this means that entering e.g. 2015 will trigger calls for year=2, year=20, year=201 and year=2015. (This is OK.)
The test
I'm using page objects - one for the inputs and one for the output. At the start of the test, I wait for a prompt to be present on the screen (please enter some data) as that is generated by JavaScript that checks the state of the input fields - so I know that the page has loaded and JavaScript has run.
The wait for a prompt is made immediately after the page object is created for the output. This is the relevant method in the page object:
// Wait until the prompt / help text is displayed. Assumes that the prompt text always contains the word "Please"
public void waitForText() {
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("resultContainer"), "Please"));
}
The method for setting the year is
public void setYear(String year){
WebElement yearField = driver.findElement(By.id(yearInputId));
if (yearField == null) {
// This should never happen
Assert.fail("Can't find year input field using id " + yearInputId);
} else {
yearField.sendKeys(new String [] {year});
driver.findElement(By.id(ageInputId)).click(); // click somewhere else
}
}
and there's a corresponding one for age.
I have a series of methods that wait for things to happen, which don't seem to have prevented the problem (below). These do things like wait for the current result values to be different from a previous snapshot of them, wait for a certain number of results to be returned etc.
I create a driver for Chrome as follows:
import org.openqa.selenium.chrome.ChromeDriver;
// ...
case CHROME: {
System.setProperty("webdriver.chrome.driver", "C:\\path\\chromedriver.exe");
result = new ChromeDriver();
break;
}
The problem
Some of the time, things work OK. Some of the time, both inputs are filled in with sensible values by the test, but the "there are 0 results" message is displayed. Some of the time, the test hangs part-way through filling in the inputs. It seems to be fine when I'm testing with Firefox, but Chrome often fails.
The fact that there is unpredictable behaviour suggests that I'm not controlling all the things I need to (and / or my attempts to control things are wrong). I can't see that I'm doing anything particularly weird, so someone must have hit these kinds of issue before.
Is there a browser issue I'm not addressing?
Is there something I'm doing wrong in setting the values?
Is there something I'm doing wrong in my test choreography?

It could be that when you start typing, the script is still loading or that there's a pending Ajax call when you start handling the next field or validation.
You could try to synchronize the calls with a low level script :
const String JS_WAIT_NO_AJAX =
"var callback = arguments[0]; (function fn(){ " +
" if(window.$ && window.$.active == 0) " +
" return callback(); " +
" setTimeout(fn, 60); " +
"})();";
JavascriptExecutor js = (JavascriptExecutor)driver;
driver.manage().timeouts().setScriptTimeout(20, TimeUnit.SECONDS);
js.executeAsyncScript(JS_WAIT_NO_AJAX);
driver.findElement(By.Id("...")).sendKeys("...");
js.executeAsyncScript(JS_WAIT_NO_AJAX);
driver.findElement(By.Id("...")).click();

Related

What are the best practices for using waitFor{} and sleep() in geb automated testing?

Currently in the process of learning how to write automated tests using geb so this may be bit of a noob observation and question. Is it just me or when running many tests one after another seem to speed up the the execution of the tests? For example, when write a new test I'll comment out my other tests just to run a single method or two to make sure its working properly. Everything will run fine and pass. Then when I uncomment everything to run the full test, the test appears to run extremely fast and to the point where the web application I'm automating cant keep up and will cause my tests to fail due to elements not being loaded. Even when using waitFor{} blocks. i found that using sleep(1000) in certain places has helped but I feel as though there is probably a better way to approach this problem. The web application I'm working with seems to refresh the page a lot whenever the user does anything with a field which may be part of the problem that I don't really have control over. at one part in my test I need to fill out a form but the page refreshes after fill out out an input so I've written the code below that works but looks kind of meh because of all the sleep statements.
void populateRequiredFields(){
def fName = "Test"
def lName = "User"
def email = "abc#abc.com"
def question = "Do you even test bro?"
clear.click()
//sleep() to slow down test in order to get correct elements due to page refreshing
sleep(3000)
firstName << fName
sleep(1000)
lastName << lName
sleep(1000)
emailAddress << email
sleep(1000)
veryifyEmail << email
sleep(1000)
questionField << question
sleep(1000)
}
If you need to wait longer than the standard 10 seconds provided by waitFor, you can do this:
waitFor(30, 0.5){ firstName << fName }
This will wait for 30 seconds and check every half second.
I found that it's best to enclose logic that waits for the page to be in the expected state after a typically asynchronous action is performed inside of methods on page objects and modules. This way you don't litter your tests with all the waitFor {} noise and you won't forget to wait for things when you add more tests because waiting is part of the reusable logic.
So in your case:
import geb.Page
class APageThatCanBeCleared extends Page {
static content = {
clear { $(/*whatever the selector for the clearing element is*/) }
firstName { $(/*whatever the selector for the first name element is*/) }
}
void clear() {
clear.click()
waitFor { firstName.displayed }
}
}
and then in your test:
to APageThatCanBeCleared
clear()
firstName << "Test"
Using sleep() is not a good idea. Try to use waitFor {some results are present}

Condition- assert using Selenium

I want to write a script which can detect this message " System is not responding to your request. Kindly try after sometime." as shown in the screenshot below. When this message comes up then I want verify and send mail to the development team.
Snippet which I wrote for verification purpose but it is not working fine for me, pls suggest some alternative:
String s1 = d1.findElementByXPath(".//*[#id='showSearchResultDiv']").getText();
System.out.println(s1);
Remember to be careful when writing code for automation. If the scenario doesn't always show up, you cannot try and find an XPath, because you can't getText() if the object (based on the XPath) doesn't exist first. You probably need a try/catch around your code, and then put the println inside the try. This scenario will occur quite frequently, so you may want to write your own framework on top of WebDriver to handle these use cases.
If that is not the issue. Put a try/catch around the code that is failing to capture what the exception is.
You should try to wait for your element to appear before examining its text:
for (int second = 0;; second++) {
if (second >= 60) fail("timeout");
try { if (d1.findElementByXPath(".//*[#id='showSearchResultDiv']").isDisplayed()) break; } catch (Exception e) {}
Thread.sleep(1000);
}
String s1 = d1.findElementByXPath(".//*[#id='showSearchResultDiv']").getText();
System.out.println(s1);
The exact code may be different, depending on the webpage you're testing (e.g. you should remove the 'fail' line if it's OK for the element not to appear every time.

GEB assertion, waitFor

I'm learning GEB in IntelliJ and have two issues.
When I click button on the top of the page I'm redirected to very bottom of the page.
After this I need to do assertion that the site slided down.
I try to do assertion in this example:
assert page.element_on_the bottom.isDisplayed() == true
// element_on_the bottom {$('css_selector)
The above assertion always returns true even I don't click button to slide down.
I need to check if element is visible on the part of website which is actually displayed on my monitor screen. Is there a way to do this?
I try to use waitFor statement in example:
waitFor{page.element.isDisplayed()}
but it doesn't work:
geb.waiting.WaitTimeoutException: condition did not pass in 5.0 seconds (failed with exception)
instead of this I use:
Thread.sleep(3000) //which is not desirable here
and then my test passes. I think my element don't trigger any js or ajax script actions.
I'm not sure how to use waitFor that should wait for all elements to load.
Element doesn't have to be in view for is isDisplayed() to return true - it will return true as long as the element is visible on page, e.g. it's display property is not set to hidden. You will need to detect your scroll position using javascript because WebDriver does not expose scroll information. See this response for how to detect that scroll is at the bottom of the page and see this section of the Book of Geb for how to execute javascript code in the browser.
What is the exception and its stacktrace that you're getting from your waitFor {} call? It probably contains the clue on what is actually going on.
For your first problem, can you please try the following as displayed should work fine for the visibility and present should be good to check the presence of the css selector in the DOM:
waitFor { page.element_on_the bottom.isDisplayed() }
or
waitFor { page.element_on_the bottom.displayed() }
For the second problem, you need to edit your Gebconfig file, like below as the waiting time you have right now is 5 seconds that's why it's failing whereas your sleep time is way more than 5 seconds:
waiting {
timeout = 30
retryInterval = 0.1
}
or, you can also try that at the same line of the code as below:
waitFor (30, 0.1) {page.element.isDisplayed()}
Please let us know if that worked fine or not! On another note, why don't you simply write the function name from the imported class instead of always writing className.functionName()? Best of luck and Cheers!!

Wait for an element using Selenium webdriver

What is the best way to wait for an element to appear on a web page? I have read that we can use implicit wait and functions like webdriverwait, fluentwait etc and last but not the least thread.sleep()...which i use the most but want to stop using at all.
My scenario:
User logs in to a website...website checks the credentials and provides an offer to the user in the form of an overlay (kind of popup but not a separate window). I need to verify text on the the overlay.
There is a time gap between user signing in and the overlay getting displayed. what is the best approach so that selenium waits only till the time the element is not visible. As the overlay is not a separate page but part of the main page, implicit wait does not work at all.
All suggestions are welcome...:)
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(By.id("optionsBuilderSelect_input")));
I'm a professional scraper (http://nitinsurana.com) I've written 30+ softwares using selenium and I've never faced any such issue, anyways above is a sample code.
All I can think of is that what until condition has to be checked because many a times elements are already visible, but they are not clickable and things like that. I guess you should give different options a try and I hope you'll find the one required.
Always start by using a implicit wait. I think Selenium defaults to 5 seconds and so if you do a driver.findElement(), the implication is that it will wait up to 5 seconds. That should do it. If you are experiencing a scenario where the time it takes is unpredictable, then use FluentWait (with the same 5 second timeout) but also using the .ignoring method and wrap that inside a while loop . Here is the basic idea:
int tries=0;
while ( tries < 3 ) {
//fluent wait (with .ignoring) inside here
tries ++1;
}
public boolean waitForElement(WebElement ele, String xpath, int seconds) throws InterruptedException{
//returns true if the xpath appears in the webElement within the time
//false when timed out
int t=0;
while(t<seconds*10){
if(ele.findElements(By.xpath(xpath)).size()>0)
return true;
else{
Thread.sleep(100);
t++;
continue;
}
}
System.out.println("waited for "+seconds+"seconds. But couldn't find "+xpath+ " in the element specified");
return false;
}
You could wait for the presence of the element to appear as follows:
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(By.id("someId")));

How to update UI from a new thread vb.NET website

My application works like this:
Upload Excel file + convert to DataTable
Start new thread
Begin loop through DataTable
Update UI (Label) to show "Processing row [i] of [n]"
Next
End loop
The bold is what I'm not able to do. I've looked around online for updating UI elements from worker threads, but all the results I can seem to find are for Windows Forms, rather than a web project. Is this possible?
yes, you can do it, and actually it is not difficult. you can use ajax toolbox to do it easily. simply use an updatepanel, and update progress.
check http://ajaxcontroltoolkit.codeplex.com/
an example: http://www.asp.net/ajax/documentation/live/overview/updateprogressoverview.aspx
I found a workaround using jQuery AJAX and asp.NET WebMethods and a session variable.
I used a method from one of my previous questions, by having a WebMethod check on a Session variable that was updated by the worker thread.
Worker thread:
Session["progress"] = "{\"current\":" + (i + 1) + ", \"total\":" + dt.Rows.Count + "}"
WebMethod:
[WebMethod]
public static string GetProgress()
if (HttpContext.Current.Session["progress"] == null) {
return "{\"current\":1,\"total\":1}";
} else {
return HttpContext.Current.Session["progress"];
}
}
my jQuery basically looped calling that AJAX WebMethod every second. It would start on page load and if the current = total then it would display "Completed" and clear the loop, otherwise it shows "Processing row [current] of [total]". I even added a jQuery UI Progressbar
This is kind of a manual solution but it solves my problem, with little overhead. An unexpected but nice piece is that since it is utilizing a Session variable, and the WebMethod checks on page load, if the worker thread is active then the progressbar will show even if you navigate away and come back to the page.