Not catching NoSuchElementException - java

I am scraping fixtures of one website and then using another website to check each team's form. The issue I am having is that not all teams exist on the form website and I am getting a NoSuchElementException for the teams whose xPath clearing doesn't exist on the URL not found page. I am trying to catch the exception but the program still breaks.
I have added a try catch but it doesn't solve my problem, the program breaks as soon as it arrives as a non-found team.
for(int i = 0; i < fixtures.getAwayTeams().size(); i++)
{
driver.navigate().to(FORMURL.concat( (fixtures.getAwayTeams().get(i)).replace( ' ', '+' )));
for (int j = 1; j < 11; j++) {
String xPath = FORMXPATHONE.concat( String.valueOf( j ) ).concat(FORMXPATHTWO);
try {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(xPath)));
forms = driver.findElementsByXPath( xPath );
} catch(NoSuchElementException | StaleElementReferenceException e) {
awayTeamForm.add("No Form for Team");
}
for (WebElement languageElement : forms) {
ArrayList <String> wld = new ArrayList<String>();
wld.add( languageElement.getText() );
String listedForm = String.join(",", wld );
awayTeamForm.add(listedForm);
}
}
}
}
Caused by: org.openqa.selenium.NoSuchElementException: Unable to locate element: //*[#id="results"]/table/tbody/tr[1]/td[6]

You can check that the element is present on the page or not by first fetching the element list and then checking the size of that list, if its greater than 0 then the element is present else the element is not present on the page. By this you don't need to catch the exception as well.
You can do it like:
List<WebElement> elementList = driver.findElements(By.xpath("xPath"));
if(elementList.size()>0){
// Element is present
}
else{
// Element is not present
}

Your try-catch statement looks fine. Which means, the issue has to be somewhere else.
You are using selenium, which means there are two Exceptions called NoSuchElementException available. Check your imports. Most likely the problem you have is, that you do import java.util.NoSuchElementException instead of org.openqa.selenium.NoSuchElementException

Try catch the whole loop body and debug to see if you are catching the right exception and on the right line.
Are you sure that only
forms = driver.findElementsByXPath( xPath );
can raise the exception?

try this :
try {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(xPath)));
forms = driver.findElementsByXPath( xPath );
} catch(NoSuchElementException | StaleElementReferenceException | TimeoutException e) {
awayTeamForm.add("No Form for Team");
}

Related

Selenium | Element not interactable error: Explored all the options of stack overflow

I am trying to get all drop downs from a web page and select a value from them in one go.
I have attached a code snippet which gets all the dropdowns which are bootstrapped and under tag on the web page.
I want to access children of each ul tag which are under li tag and click on any of those children.
I am attaching the screen shot taken from web site.
It always says element not interactable eventhough it is clikable element.
Please help.
Application screenshot
Code:
List<WebElement> dropDowns = webDriver.findElements(By.xpath("//ul[contains(#class,'dropdown')]"));
try{Thread.sleep(5000);}catch (Exception e){};
for(WebElement webElement : dropDowns){
try{
List<WebElement> elementList = webElement.findElements(By.xpath("//ul[contains(#class,'dropdown')]//li"));
for (int i = 0 ; i < elementList.size();i++){
elementList.get(i).click();
Thread.sleep(3000);
}
}
catch (Exception e){
System.out.println("-----------Error----------");
continue ;
}
}
try{Thread.sleep(10000);}
catch (Exception e){}
webDriver.quit();
}
I see below issues in your code.
You are trying to use the webElement from dropDowns list which will through stale element exception if you use webElement in the for loop.
Your code will perform the operation on the first operation on the first dropdwn all the times as you are not getting the downdown based on the index.
you mentioned you want to select an item in the list but you are clicking on the each item in the dropdown.
Please try with the below logic.
int dropDowns = webDriver.findElements(By.xpath("//ul[contains(#class,'dropdown')]")).size();
try{Thread.sleep(5000);}catch (Exception e){};
JavascriptExecutor js = (JavascriptExecutor) webDriver;
for(int dropdownIndex =0; dropdownIndex < dropDowns; dropdownIndex++){
WebElement dropdown = webDriver.findElements(By.xpath("//ul[contains(#class,'dropdown')]")).get(dropdownIndex);
try{
List<WebElement> elementList = dropdown.findElements(By.xpath(".//li"));
for (int i = 0 ; i < elementList.size();i++){ // not sure if you really want to click each item in the dropdown, hence not modified this part.
WebElement item = elementList.get(i);
js.executeScript("arugments[0].click()",item);
Thread.sleep(3000);
}
}
catch (Exception e){
System.out.println("-----------Error----------");
continue ;
}
}

If Selenium driver does not find Element ( If - else if) move on, yet it throws a can't find element error

Long story short - I have a button that doesn't have ID's and has a compound class( So selenium hates it / cant find it). So I use the XPath selector for it that works great
driver.findElement(By.xpath("//input[#value='Continue to Payment']")).click()
But the button changes depending on the language being used.
So at the moment, I have
if (driver.findElement(By.xpath("//input[#value='Continue to Payment']")).isDisplayed()){
driver.findElement(By.xpath("//input[#value='Continue to Payment']")).click();
}
else if (driver.findElement(By.xpath("//input[#value='Paiement']")).isDisplayed()){
driver.findElement(By.xpath("//input[#value='Paiement']")).click();
}
else if ( same thing as above but for another language)
But when Selenium errors out after going through the first if statement with:
no such element: Unable to locate element:{"method":"xpath","selector":"//a[contains(text(),'Checkout')]"}
I know the element is not there.. so I dont want it to do anything & move on to the next if else statement.
What am I missing here?
try {
if (driver.findElement(By.xpath("//input[#value='Continue to Payment']")).isDisplayed()){
driver.findElement(By.xpath("//input[#value='Continue to Payment']")).click();
}
else if (driver.findElement(By.xpath("//input[#value='Paiement']")).isDisplayed()){
driver.findElement(By.xpath("//input[#value='Paiement']")).click();
}
else
System.out.println("Button not found");
} catch(NoSuchElementException | StaleElementReferenceException e) {
System.out.println("Impossible to click the pop-up. Reason: " + e.toString());
}
Try above solution, Hopefully it will work for you. In your example wrong code has been written for else if (driver.findElement(By.xpath("//input[#value='Paiement']")).isDisplayed).
You can use separate short methods to achieve expected results and log errors.
public WebElement getElement(WebDriver driver, String XPATH, int timeoutInSeconds){
WebElement elem = null;
try{
WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
elem = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(XPATH));
} catch (Exception e){
// log or print error.
}
return elem;
}
You can then call it like
WebElement e = getElement(driver, "//input[#value='Continue to Payment']", 10);
if (e != null) {
e.click();
} else {
e = getElement(driver, "//input[#value='Paiement']", 5);
if (e != null) {
e.click();
} /// and so on....
}
This way you can adjust the wait time for each element and also not fall into errors if any one element is missing because of language.

Selenium Webdriver: How to get the dynamic id using xpath?

I am trying to get the id of an element which starts with 'u_' and ends with '_5' and in between data changes alphabetically.So, sometimes i see 'u_d_5' and sometime 'u_6_5' . In that case, how would get the dynamic id?
I know there are some methods like starts-with or ends-with but they aren't working at all for me. Could anyone please suggest me some idea in this?
code snippet:
WebElement cls=ff.findElement(By.xpath("//*[#id='u_6_5']"));
whole code:
String s=System.getProperty("user.dir");
System.setProperty("webdriver.chrome.driver", s+"\\ChromeDriver\\chromedriver.exe");
ChromeDriver ff=new ChromeDriver();
try{
ff.manage().window().maximize();
ReadfrmExcel rd=new ReadfrmExcel();//reading data
String[][] readata=rd.excelRead();
for(int i=1; i<readata.length; i++)
{
ff.get("http://www.facebook.com");
Thread.sleep(1000);
ff.findElementByXPath("//*[#id='email']").sendKeys(readata[i][0]);
ff.findElementByXPath("//*[#id='pass']").sendKeys(readata[i][1]);
ff.findElement(By.id("u_0_v")).click();
System.out.println("Waiting for element to appear");
Thread.sleep(3000);
WebElement element=ff.findElement(By.id("userNavigationLabel"));
element.click();
System.out.println("Clicked drop down");
//ff.findElementByXPath("//*[#id='userNavigationLabel']").click();
System.out.println("sleeping 5 secs");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
WebElement cls=ff.findElement(By.xpath("//*[starts-with(#id,'u_') and ends-with(#id, '_5']"));
boolean vis=cls.isDisplayed();
System.out.println(vis);
Thread.sleep(8000);
System.out.println("Sleeping 8 secs");
cls.click();
System.out.println("After clicking");
System.out.println("Successfully logged out!!");
//ff.close();
ff.close();
}
}
catch(Exception e){
System.out.println(e);
}
you can use xpath's starts-with and ends-with methods:
WebElement cls=ff.findElement(By.xpath("//*[starts-with(#id,'u_') and ends-with(#id, '_5')]"));
if this is not working, your browser might only support xpath 1.0 (see this answer for details) -> then you can only use starts-with
WebElement cls=ff.findElement(By.xpath("//*[starts-with(#id,'u_')]"));
if you definitely need to check the end of the id, then you can try the following xpath instead:
//*[starts-with(#id, 'u_') and substring(#id, string-length(#id) - 1) = '_5']
I have tried to get all ids, which i have to use.
First get the tag name in which your id attribute has been defined.
java.util.List links = ff.findElements(By.tagName("span"));
ArrayList arrList = new ArrayList();
for (int i = 0;i < links.size();i++){
if(links.get(i).getAttribute("id").startsWith("u_") &&
links.get(i).getAttribute("id").endsWith("_5")){
arrList.add(links.get(i).getAttribute("id"));
}
}
Now you will find all the ids which are starts with "u_" and ends with"_5".
System.out.println("arrList elements : "+arrList);

Problematic parsing of html table with selenium webdriver

I am using selenium webdriver with java to test a web application in my company and I face a very strange problem. The web application after logging in displays this table with the values as shown in the picture in the link below:
https://drive.google.com/file/d/0B0i_2gNTlx1Sek9EQVQ1ZlY1a0E/view?usp=sharing
I have wrote this code that parses the table with xpath because the table's rows and td cells are id-less.
//Parsing the table.
int increment = 0;
int i = 0;
for(increment=1; increment <= 16; increment++){
StringBuilder nsb = new StringBuilder("");
StringBuilder sb = new StringBuilder("");
for(i=1; i <= 6; i++){
try {
WebElement f = wd.findElement((By.xpath("/html/body/div[1]/div/div[2]/div/div[2]/div[2]/div[2]/div/div[1]/form/div/div/table/tbody/tr["+increment+"]/td["+i+"]")));
sb.append(f.getText().replaceAll("\\n", " ")).append(" ");
} catch (StaleElementReferenceException ed) {
ed.getSuppressed();
}
}
System.out.println(sb);
}
System.out.println();
The problem now is that when I print the values of each row sometimes and in random order i lose some of the values on the output as shown in the picture i post below(for example if i re-run the program the second field in the second row called SAB will be missing).
Correct output is
https://drive.google.com/file/d/0B0i_2gNTlx1SQmFoZDd0UkgzVXM/view?usp=sharing
I tried instead of getText method the getAttribute("textContent") but i face the same random problem.
Does anyone have any idea why is this happening?
Sorry for the links but I didn't have any alternative to show you my problem..I can also post a random faulty output I got during testing if it's needed..
One thought,
why did you add ?
catch (StaleElementReferenceException ed) {
ed.getSuppressed();
}
Are you getting this exception if not catching?
if yes, then
might be your page or element is getting refreshed
and when you are referring f on second line to getText() you may get StaleElementReferenceException, But as you are suppressing it your loop continues and value is lost because of exception.
you can try replacing
WebElement f = wd.findElement((By.xpath("/html/body/div[1]/div/div[2]/div/div[2]/div[2]/div[2]/div/div[1]/form/div/div/table/tbody/tr["+increment+"]/td["+i+"]")));
sb.append(f.getText().replaceAll("\\n", " ")).append(" ");
with single statement
sb.append(wd.findElement((By.xpath("/html/body/div[1]/div/div[2]/div/div[2]/div[2]/div[2]/div/div[1]/form/div/div/table/tbody/tr["+increment+"]/td["+i+"]"))).getText().replaceAll("\\n", " ")).append(" ");
Probably this will avoid staleElement Exception if issue is caused by it.

Getting stale element reference: element is not attached to the page document exception

In my application, when i open the page,left hand side are displayed list of tabs.
By default,one tab is opened status and other tabs are closed status,so i am looking to find the opened status tab class name and clicked the tab, it has closed,then had to give the another tab id to open.
While executing the code,I am getting the "stale element reference: element is not attached to the page document" exception.
I have tried with implicit wait option as well.
Could any one please help on that issue to resolve?
driver.manage().timeouts().implicitlyWait(1000,TimeUnit.SECONDS);
WebElement element5 = driver.findElement(By.className("TopItemActive"));
if(element5.isEnabled())
{
element5.click();
}
driver.manage().timeouts().implicitlyWait(2000,TimeUnit.SECONDS);
WebElement element6 = driver.findElement(By.id("id_16_cell"));
element6.click();
System.out.println("Tab opened");
My guess is that your tabs are created and removed with JavaScript. What Webdriver does is to download the webpage and store it in the instance. If something is changed due to javascript webdriver isnt always aware of it.
This could work as a simple solution
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.refreshed(ExpectedConditions.elementToBeClickable(by)));
What i have found is there isnt much to do about it. I catch the exception thrown and try again. So I created a new function for "click"
public String click(By by){
String text = "";
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
boolean unfound = true;
int tries = 0;
while ( unfound && tries < 3 ) {
tries += 1;
try {
wait.until(ExpectedConditions.refreshed(ExpectedConditions.visibilityOfElementLocated(by)));
text = driver.findElement(by).click();
unfound = false;
logger.info("Click element "+stripBy(by));
} catch ( StaleElementReferenceException ser ) {
logger.error( "ERROR: Stale element exception. " + stripBy(by) );
} catch ( NoSuchElementException nse ) {
logger.error( "ERROR: No such element exception. " + stripBy(by)+"\nError: "+nse );
} catch ( Exception e ) {
logger.error( e.getMessage() );
}
}
if(unfound)
Assert.assertTrue(false,"Failed to locate element by locator " + stripBy(by));
return text;
}

Categories

Resources