I need to click on particular element of an dynamically loaded page.Web element generated when we scroll the page.It similar like an jabong webpage.
I try to do that on jabong webpage this is my code
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.navigate().to("http://www.jabong.com/men/clothing/"
+ "?source=topnav");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
System.out.println("Close the modal popup");
driver.findElement(By.id("jab-vchr-cls")).click();
driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
/**
* while(true) loop is required to search the
* element until element found.We put find
* element within try-catch and if it get
* exception it scroll the page and again
* try to find the element.
*/
while(true) {
((JavascriptExecutor)driver).executeScript("window.scrollBy(0,100)", "");
try {
WebElement element = driver.findElement(By.xpath("//*[#id='http: //static3.jassets.com/p/The-Indian-Garage-Co.-Checks-Red-Casual-Shirt-2889-679124-1-catalog.jpg']/img"));
Wait<WebDriver> wait_element=new WebDriverWait(driver, 10);
wait_element.until(ExpectedConditions.elementToBeClickable(element));
element.click();
System.out.println("!!!!!!!!!!!!!!At Last Get Success!!!!!!!!!!!!!!!!");
break;
}
catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(ex.getMessage());
}
}
}
}
My question is
1.Is there any better way to do this things?
2.How to make this script faster?
you can do this way if you want to avoid while(true) though I donot think there is any problem with this loop.
boolean reachedbottom = Boolean.parseBoolean(js.executeScript("return $(document).height() == ($(window).height() + $(window).scrollTop());").toString());
while (!reachedbottom) {
((JavascriptExecutor) driver).executeScript("window.scrollBy(0,600)", "");
try {
reachedbottom=Boolean.parseBoolean(js.executeScript("return $(document).height() == ($(window).height() + $(window).scrollTop());").toString());
WebElement element = driver.findElement(By.xpath("//*[#id='http://static3.jassets.com/p/The-Indian-Garage-Co.-Checks-Red-Casual-Shirt-2889-679124-1-catalog.jpg']/img"));
Wait<WebDriver> wait_element = new WebDriverWait(driver, 5);
wait_element.until(ExpectedConditions.elementToBeClickable(element));
element.click();
System.out.println("!!!!!!!!!!!!!!At Last Get Success!!!!!!!!!!!!!!!!");
break;
} catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
System.out.println(ex.getMessage());
}
}
In the Getting Started with Selenium framework, the AutomationTest#waitForElement method is a great way to handle things. It's an alternative to the webdriver wait, but works all the same.
/**
* Private method that acts as an arbiter of implicit timeouts of sorts.. sort of like a Wait For Ajax method.
*/
private WebElement waitForElement(By by) {
int attempts = 0;
int size = driver.findElements(by).size();
while (size == 0) {
size = driver.findElements(by).size();
if (attempts == MAX_ATTEMPTS) fail(String.format("Could not find %s after %d seconds",
by.toString(),
MAX_ATTEMPTS));
attempts++;
try {
Thread.sleep(1000); // sleep for 1 second.
} catch (Exception x) {
fail("Failed due to an exception during Thread.sleep!");
x.printStackTrace();
}
}
if (size > 1) System.err.println("WARN: There are more than 1 " + by.toString() + " 's!");
return driver.findElement(by);
}
You can take it out of the infinite loop. If a page doesn't load something within 10 seconds then i'd say it's an app issue that needs to be rectified. Take it out out of the infinite loop, and using something like waitForElement specified above, or just use a WebDriverWait class.
Furthermore, you shouldn't ever have to scroll to an element. I still have yet to find a reason to do something like this. As long as the element is on the DOM, it should be able to be operated on.
Related
I working in selenium and now for checking visibility of element i use following wait until:
#FindBy (css=".delete-basket-modal-btn") WebElement deleteItemFromBasketCancelButton;
public void clickDeleteItemFromBasketCancelButton() throws InterruptedException {
wait.until(ExpectedConditions.elementToBeClickable(deleteItemFromBasketCancelButton));
deleteItemFromBasketCancelButton.click();
}
that's not good idea, this function is not checking for presence of element, so sometimes i get 'stale element reference element is not attached to the page document'
Now i trying to create universal function which will be inherited by all of mine page object class. In this function i need checking (5 sec) for presence, enability, clickability and visibilty of WebElement passed in argument.
For this moment i have new function below, but i dont know that is good approach for my problem
public void verifyElement(WebElement element) throws InterruptedException {
boolean isPresent = false;
for (int i = 0; i < 5; i++) {
try {
if (element != null) {
isPresent = true; // metoda do czekania na element
break;
}
} catch (Exception e) {
// System.out.println(e.getLocalizedMessage());
Thread.sleep(1000);
}
}
Assert.assertTrue(isPresent, "\"" + element + "\" is not present.");
boolean isEnabled = false;
for (int i = 0; i < 5; i++) {
try {
if (element.isEnabled()==true) {
isEnabled = true;
break;
}
}catch (Exception e) {
Thread.sleep(1000);
}
}
Assert.assertTrue(isEnabled, "\"" + element + "\" is not enabled.");
}
Do you have any suggestion or similar problem for this issue?
StaleElementReferenceException doesn't (necessarily) mean the element is not present, it means the DOM had changed/refreshed since the element was located, so the element reference which the driver holds is no longer valid. This is a disadvantage of using PageFactory model.
The solution is to locate the element just before the click operation, however this will break the consistency of the page object. Instead of using FindBy send By to the method and locate the element there
public void clickDeleteItemFromBasketCancelButton(By by) throws InterruptedException {
WebElement deleteItemFromBasketCancelButton = wait.until(ExpectedConditions.elementToBeClickable(by));
deleteItemFromBasketCancelButton.click();
}
The first written code is enough. To overcome stale element exception write code in try/catch block and use ExpectedConditions.stalenessOf(deleteItemFromBasketCancelButton) for presence, enability, clickability and visibilty (for any type of operation).
Try below one, hope it's help for you.
try{
wait.until(ExpectedConditions.elementToBeClickable(deleteItemFromBasketCancelButton));
deleteItemFromBasketCancelButton.click();
}
catch(Exception e){
wait.until(ExpectedConditions.refreshed(ExpectedConditions.stalenessOf(deleteItemFromBasketCancelButton)))
deleteItemFromBasketCancelButton.click();
}
Am having an issue where I need to perform a click using Selenium Java on the link "PrestaShop" shown below. It's in an IFrame and my code is also below the picture.
Link to be clicked
When inspect the link using FireBug, it shows like below
Inspect using FireBug
And below is my code
try {
List<WebElement> frames = getAllFrames();
for (int i = 0; i < frames.size(); i++) {
WebElement frame = frames.get(i);
driver.switchTo().frame(frame);
if (driver.findElement(By.xpath(".//*[#classname='_1drp _5lv6']/a")).getSize() != null) {
driver.findElement(By.className(".//*[#classname='_1drp _5lv6']/a")).click();
} else {
driver.switchTo().defaultContent();
}
}
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
}
The code is getting all frames on the page and verify if the link "PrestaShop" is presence on the frame. If yes then it needs to fire a click on the link. Now, instead it returns error message - Unable to locate element: .//*[#classname='_1drp _5lv6']/a
Can please help to advise how can I fire the click successfully on the link?
While checking the presence of element, try using findElements instead of findElement. Below code might give you some idea.
List<WebElement> frames = getAllFrames();
for (int i = 0; i < frames.size(); i++) {
WebElement frame = frames.get(i);
driver.switchTo().frame(frame);
//use driver.findElements
if (driver.findElements(By.xpath(".//*[#classname='_1drp _5lv6']/a")).getSize() != null) {
driver.findElement(By.xpath("//*[contains(text(),'PrestaShop')]")).click();
} else {
driver.switchTo().defaultContent();
}
}
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
}
Hope this helps you. Thanks.
You can use following updated code:
List<WebElement> frames = getAllFrames();
for (int i = 0; i < frames.size(); i++) {
WebElement frame = frames.get(i);
driver.switchTo().frame(frame);
if (driver.findElement(By.xpath("//*[contains(text(),'PrestaShop')]")).getSize() != null) {
driver.findElement(By.xpath("//*[contains(text(),'PrestaShop')]")).click();
} else {
driver.switchTo().defaultContent();
}
}
} catch (NoSuchElementException ex) {
System.out.println(ex.getMessage());
}
Hope it will work for you.
thanks for your comment. I realized its because of the FB link was loaded too slow and hence the code fails. It's able to click now with below code if I added a Thread.sleep(30000) there.
if (driver.findElements(By.xpath(".//*[#class='lfloat']/div/a")).size() > 0) {
System.out.println("Found elements.");
driver.findElement(By.xpath("//*[contains(text(),'PrestaShop')]")).click();
} else {
System.out.println("Element not found.");
driver.switchTo().defaultContent();
}
However, if I want a FluentWait, then below code will just stop if the condition was not met
if (wait.ignoring(StaleElementReferenceException.class).ignoring(TimeoutException.class)
.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(".//*[#class='lfloat']/div/a")))
.isDisplayed()) {
System.out.println("Found elements.");
driver.findElement(By.xpath("//*[contains(text(),'PrestaShop')]")).click();
} else {
System.out.println("Element not found.");
driver.switchTo().defaultContent();
}
It just return message Expected condition failed: waiting for visibility of element located by By.xpath: .//*[#class='lfloat']/div/a (tried for 30 second(s) with 500 MILLISECONDS interval) and then not continue the loop. Can I know what's the way to make the code to continue even if the condition was not met?
I saw one os the posts before regarding stale element exception and used the retry code for handling it. But inspite of keeping the count at 20 , stale element exception still persists. I can see that the element2 is loaded in the webpage being tested .But its still id'd as stale element. The code works in case of element1 sometimes. but never for element2
code:
for (i = 1; i < 7; i++)
{
sServiceID = ExcelUtils.getCellData(i,Constant.Col_ServiceID);
System.out.println("sServiceID:"+sServiceID);
ServiceID_Filter().clear();//function returns element
ServiceID_Filter().sendKeys(sServiceID);
BaseClass.driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
Thread.sleep(3000);
ApplyFilters_element().click();
Thread.sleep(3000);
boolean result = false;
int attempts = 0;
while(attempts < 20) {
System.out.println("inside stale check loop");
BaseClass.driver.manage().timeouts().implicitlyWait(20,TimeUnit.SECONDS);
try {
if(element1.isDisplayed()||element2.isDisplayed()) //either one of the elements will be loaded
{
System.out.println("not stale "+Table_widget.ExportButton().isDisplayed());
result = true;
break;
}
} catch(StaleElementReferenceException e) {
System.out.println("stale at attempt "+attempts);
}
attempts++;
}
if(result==true)
{
if(element1.isDisplayed())
{
element3.click();
System.out.println(" button clicked");
Thread.sleep(1000);
}
else
if(element2.isDisplayed())
{ element3.click();
System.out.println("No records found");
Thread.sleep(1000);
}
}
}
In my humble opinion the problem is here:
BaseClass.driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);
Thread.sleep(3000);
ApplyFilters_element().click();
Thread.sleep(3000);
First of all you are using implicit wait plus thread sleep which is a recipe for disaster. This is what is causing your stale elements exceptions, try something like this below:
public boolean waitForElement(String elementXpath, int timeOut) {
try{
WebDriverWait wait = new WebDriverWait(driver, timeOut);
boolean elementPresent=wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(elementXpath)).isDisplayed());
System.out.printf("%nElement is present [T/F]..? ")+elementPresent;
}
catch(TimeoutException e1){e1.printStackTrace();elementPresent=false;}
return elementPresent;
}
Best of luck!
After much searching and reading, I'm still unclear as to the best way to handle a failed assertion using Webdriver. I would have thought this was a common and core piece of functionality. All I want to do is:
look for an element
if present - tell me
if not present - tell me
I want to present the results for a non technical audience, so having it throw 'NoSuchElementExceptions' with a full stack trace is not helpful. I simply want a nice message.
My test:
#Test
public void isMyElementPresent(){
// WebElement myElement driver.findElement(By.cssSelector("#myElement"));
if(driver.findElement(By.cssSelector("#myElement"))!=null){
System.out.println("My element was found on the page");
}else{
System.out.println("My Element was not found on the page");
}
}
I still get a NoSuchElementException thrown when I force a fail. Do I need a try/catch as well? Can I incorporate Junit assertions and/or Hamcrest to generate a more meaningful message without the need for a System.out.println?
I have encountered similar situations. According to the Javadoc for the findElement and findElements APIs, it appears that the findElement behavior is by design. You should use findElements to check for non-present elements.
Since in your case, there's a chance that the WebElement is not present, you should use findElements instead.
I'd use this as follows.
List<WebElement> elems = driver.findElements(By.cssSelector("#myElement"));
if (elems.size == 0) {
System.out.println("My element was not found on the page");
} else
System.out.println("My element was found on the page");
}
you can do something to check if element exists
public boolean isElementExists(By by) {
boolean isExists = true;
try {
driver.findElement(by);
} catch (NoSuchElementException e) {
isExists = false;
}
return isExists;
}
What about using an xPath inside of a try-catch, passing the elementype, attribute and text as follows?
try {
driver.FindElement(
By.XPath(string.Format("//{0}[contains(#{1}, '{2}')]",
strElemType, strAttribute, strText)));
return true;
}
catch (Exception) {
return false;
}
Even running it in a try block, it behaves as if unhandled,
neither of the catch blocks runs when the selenium exception occurs.
try {
wait.Until(webDriver => webDriver.PageSource.Contains(waitforTitle));
wait.Until(webDriver => webDriver.FindElement(By.Id(waitforControlName)).Displayed);
}
catch (OpenQA.Selenium.NoSuchElementException nse) {
nse = nse = null;
success = false;
}
catch (Exception ex) {
ex = ex = null;
success = false;
}
I've been testing an application involving multiple ajax calls, so I required wait condition so that elements are present/visible once the ajax call is made. I used both methods implicitwait and explicitwait but none of them seem to be working for me as one or the other exceptions are generated as follows:
1.Unable to locate element
2.Element is disabled and so may not be used for actions
Implicit wait used as follows:
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
WebElement we = driver.findElement(By.name("q"));
PROBLEM:
When I test this code, after browser opens, it throws exception in 2 seconds.
Result:Exception generated
Explicit Wait
WebDriverWait wait = new WebDriverWait(driver, /*seconds=*/3);
WebElement element = wait.until(presenceOfElementLocated(By.name("q"));
PROBLEM:
When I test this code, after browser opens, it throws exception in 2 seconds
Result:Exception generated.
Also used visibilityOfElementLocated but it does not work for me.
Has anybody faced this issue or anybody has a solution for this??
I can't say that I have faced that issue before but I also wrote my own custom DOM polling class. Here's what I do.
private int Timer = 180;
private bool CheckForElement(WebDriver driver,string byType,string selector)
{
bool elementFound = false;
for (int i = Timer - 1; i > 0; i--)
{
if (!itemFound)
{
Thread.Sleep(1000); //sets the loop to check every second this can be done at a much faster or slower rate depending on your preferences
if (byType.ToLower() == "id")
{
try{
WebDriver element = driver.FindElement(By.Id(selector);
if(element.Displayed)
{
elementFound = true;
}
}
catch {
//Do Nothing Here as we don't need to handle the exception
}
}
else if (byType.ToLower() == "tagname")
{
try{
WebDriver element = driver.FindElement(By.TagName(selector);
if(element.Displayed)
{
elementFound = true;
}
}
catch {
//Do Nothing Here as we don't need to handle the exception
}
}
else if (byType.ToLower() == "cssselector")
{
try{
WebDriver element = driver.FindElement(By.cssSelector(selector);
if(element.Displayed)
{
elementFound = true;
}
}
catch {
//Do Nothing Here as we don't need to handle the exception
}
}
else if (byType.ToLower() == "classname")
{
try{
WebDriver element = driver.FindElement(By.ClassName(selector);
if(element.Displayed)
{
elementFound = true;
}
}
catch {
//Do Nothing Here as we don't need to handle the exception
}
}
}
else
{
i = 0; //stops the loop when the element is found
}
}
return elementFound ;
}